12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <math.h> 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <map> 890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/singleton.h" 11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/synchronization/lock.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/speech/tts_platform.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "library_loaders/libspeechd.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread; 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNotSupportedError[] = 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Native speech synthesis not supported on this platform."; 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)struct SPDChromeVoice { 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string name; 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string module; 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}; 2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TtsPlatformImplLinux : public TtsPlatformImpl { 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool PlatformImplAvailable() OVERRIDE; 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool Speak( 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int utterance_id, 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& utterance, 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& lang, 38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const VoiceData& voice, 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const UtteranceContinuousParameters& params) OVERRIDE; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool StopSpeaking() OVERRIDE; 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) virtual void Pause() OVERRIDE; 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) virtual void Resume() OVERRIDE; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool IsSpeaking() OVERRIDE; 44a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) virtual void GetVoices(std::vector<VoiceData>* out_voices) OVERRIDE; 45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void OnSpeechEvent(SPDNotificationType type); 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Get the single instance of this class. 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static TtsPlatformImplLinux* GetInstance(); 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TtsPlatformImplLinux(); 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~TtsPlatformImplLinux(); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Initiate the connection with the speech dispatcher. 56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void Initialize(); 57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Resets the connection with speech dispatcher. 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Reset(); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static void NotificationCallback(size_t msg_id, 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t client_id, 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SPDNotificationType type); 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static void IndexMarkCallback(size_t msg_id, 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t client_id, 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SPDNotificationType state, 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) char* index_mark); 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static SPDNotificationType current_notification_; 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::Lock initialization_lock_; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LibSpeechdLoader libspeechd_loader_; 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SPDConnection* conn_; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // These apply to the current utterance only. 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string utterance_; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int utterance_id_; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Map a string composed of a voicename and module to the voicename. Used to 8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // uniquely identify a voice across all available modules. 8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) scoped_ptr<std::map<std::string, SPDChromeVoice> > all_native_voices_; 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) friend struct DefaultSingletonTraits<TtsPlatformImplLinux>; 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplLinux); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SPDNotificationType TtsPlatformImplLinux::current_notification_ = 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SPD_EVENT_END; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TtsPlatformImplLinux::TtsPlatformImplLinux() 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : utterance_id_(0) { 95b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) BrowserThread::PostTask(BrowserThread::FILE, 96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) FROM_HERE, 97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::Bind(&TtsPlatformImplLinux::Initialize, 98b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::Unretained(this))); 99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 100b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void TtsPlatformImplLinux::Initialize() { 102b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::AutoLock lock(initialization_lock_); 103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!libspeechd_loader_.Load("libspeechd.so.2")) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_ = libspeechd_loader_.spd_open( 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "chrome", "extension_api", NULL, SPD_MODE_THREADED); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!conn_) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Register callbacks for all events. 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_->callback_begin = 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_->callback_end = 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_->callback_cancel = 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_->callback_pause = 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_->callback_resume = 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &NotificationCallback; 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_->callback_im = &IndexMarkCallback; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_set_notification_on(conn_, SPD_BEGIN); 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_set_notification_on(conn_, SPD_END); 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_set_notification_on(conn_, SPD_CANCEL); 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_set_notification_on(conn_, SPD_PAUSE); 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_set_notification_on(conn_, SPD_RESUME); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TtsPlatformImplLinux::~TtsPlatformImplLinux() { 130b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::AutoLock lock(initialization_lock_); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (conn_) { 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_close(conn_); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_ = NULL; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TtsPlatformImplLinux::Reset() { 138b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::AutoLock lock(initialization_lock_); 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (conn_) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_close(conn_); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) conn_ = libspeechd_loader_.spd_open( 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "chrome", "extension_api", NULL, SPD_MODE_THREADED); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TtsPlatformImplLinux::PlatformImplAvailable() { 146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (!initialization_lock_.Try()) 147b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) bool result = libspeechd_loader_.loaded() && (conn_ != NULL); 149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) initialization_lock_.Release(); 150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return result; 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TtsPlatformImplLinux::Speak( 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int utterance_id, 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& utterance, 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& lang, 157a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const VoiceData& voice, 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const UtteranceContinuousParameters& params) { 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!PlatformImplAvailable()) { 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) error_ = kNotSupportedError; 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Speech dispatcher's speech params are around 3x at either limit. 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) float rate = params.rate > 3 ? 3 : params.rate; 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rate = params.rate < 0.334 ? 0.334 : rate; 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) float pitch = params.pitch > 3 ? 3 : params.pitch; 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pitch = params.pitch < 0.334 ? 0.334 : pitch; 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::map<std::string, SPDChromeVoice>::iterator it = 17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) all_native_voices_->find(voice.name); 17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (it != all_native_voices_->end()) { 17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) libspeechd_loader_.spd_set_output_module(conn_, it->second.module.c_str()); 17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) libspeechd_loader_.spd_set_synthesis_voice(conn_, it->second.name.c_str()); 17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Map our multiplicative range to Speech Dispatcher's linear range. 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // .334 = -100. 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 3 = 100. 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_set_voice_rate(conn_, 100 * log10(rate) / log10(3)); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) libspeechd_loader_.spd_set_voice_pitch(conn_, 100 * log10(pitch) / log10(3)); 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) utterance_ = utterance; 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) utterance_id_ = utterance_id; 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (libspeechd_loader_.spd_say(conn_, SPD_TEXT, utterance.c_str()) == -1) { 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Reset(); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TtsPlatformImplLinux::StopSpeaking() { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!PlatformImplAvailable()) 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (libspeechd_loader_.spd_stop(conn_) == -1) { 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Reset(); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void TtsPlatformImplLinux::Pause() { 204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!PlatformImplAvailable()) 205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) libspeechd_loader_.spd_pause(conn_); 207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void TtsPlatformImplLinux::Resume() { 210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!PlatformImplAvailable()) 211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) libspeechd_loader_.spd_resume(conn_); 213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TtsPlatformImplLinux::IsSpeaking() { 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return current_notification_ == SPD_EVENT_BEGIN; 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 219a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void TtsPlatformImplLinux::GetVoices( 220a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) std::vector<VoiceData>* out_voices) { 22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!all_native_voices_.get()) { 22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) all_native_voices_.reset(new std::map<std::string, SPDChromeVoice>()); 22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char** modules = libspeechd_loader_.spd_list_modules(conn_); 22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!modules) 22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (int i = 0; modules[i]; i++) { 22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* module = modules[i]; 22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) libspeechd_loader_.spd_set_output_module(conn_, module); 22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SPDVoice** native_voices = 23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) libspeechd_loader_.spd_list_synthesis_voices(conn_); 23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!native_voices) { 23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) free(module); 23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) continue; 23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (int j = 0; native_voices[j]; j++) { 23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SPDVoice* native_voice = native_voices[j]; 23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SPDChromeVoice native_data; 23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) native_data.name = native_voice->name; 23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) native_data.module = module; 24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string key; 24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) key.append(native_data.name); 24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) key.append(" "); 24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) key.append(native_data.module); 24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) all_native_voices_->insert( 24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::pair<std::string, SPDChromeVoice>(key, native_data)); 24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) free(native_voices[j]); 24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) free(modules[i]); 24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (std::map<std::string, SPDChromeVoice>::iterator it = 25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) all_native_voices_->begin(); 25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) it != all_native_voices_->end(); 25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) it++) { 25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) out_voices->push_back(VoiceData()); 25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) VoiceData& voice = out_voices->back(); 25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) voice.native = true; 25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) voice.name = it->first; 26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) voice.events.insert(TTS_EVENT_START); 26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) voice.events.insert(TTS_EVENT_END); 26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) voice.events.insert(TTS_EVENT_CANCELLED); 26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) voice.events.insert(TTS_EVENT_MARKER); 264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) voice.events.insert(TTS_EVENT_PAUSE); 265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) voice.events.insert(TTS_EVENT_RESUME); 26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TtsPlatformImplLinux::OnSpeechEvent(SPDNotificationType type) { 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TtsController* controller = TtsController::GetInstance(); 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (type) { 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case SPD_EVENT_BEGIN: 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) controller->OnTtsEvent(utterance_id_, TTS_EVENT_START, 0, std::string()); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) case SPD_EVENT_RESUME: 276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) controller->OnTtsEvent(utterance_id_, TTS_EVENT_RESUME, 0, std::string()); 277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case SPD_EVENT_END: 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) controller->OnTtsEvent( 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) utterance_id_, TTS_EVENT_END, utterance_.size(), std::string()); 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) case SPD_EVENT_PAUSE: 283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) controller->OnTtsEvent( 284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) utterance_id_, TTS_EVENT_PAUSE, utterance_.size(), std::string()); 285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case SPD_EVENT_CANCEL: 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) controller->OnTtsEvent( 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) utterance_id_, TTS_EVENT_CANCELLED, 0, std::string()); 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case SPD_EVENT_INDEX_MARK: 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) controller->OnTtsEvent(utterance_id_, TTS_EVENT_MARKER, 0, std::string()); 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TtsPlatformImplLinux::NotificationCallback( 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t msg_id, size_t client_id, SPDNotificationType type) { 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We run Speech Dispatcher in threaded mode, so these callbacks should always 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // be in a separate thread. 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_notification_ = type; 303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) BrowserThread::PostTask( 304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) BrowserThread::UI, 305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) FROM_HERE, 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&TtsPlatformImplLinux::OnSpeechEvent, 307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::Unretained(TtsPlatformImplLinux::GetInstance()), 308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) type)); 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TtsPlatformImplLinux::IndexMarkCallback(size_t msg_id, 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t client_id, 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SPDNotificationType state, 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) char* index_mark) { 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dtseng): index_mark appears to specify an index type supplied by a 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // client. Need to explore how this is used before hooking it up with existing 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // word, sentence events. 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We run Speech Dispatcher in threaded mode, so these callbacks should always 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // be in a separate thread. 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_notification_ = state; 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&TtsPlatformImplLinux::OnSpeechEvent, 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(TtsPlatformImplLinux::GetInstance()), 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state)); 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TtsPlatformImplLinux* TtsPlatformImplLinux::GetInstance() { 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return Singleton<TtsPlatformImplLinux, 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LeakySingletonTraits<TtsPlatformImplLinux> >::get(); 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TtsPlatformImpl* TtsPlatformImpl::GetInstance() { 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return TtsPlatformImplLinux::GetInstance(); 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 341