Initial commit
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
package com.wordsbaking.cordova.tts;
|
||||
|
||||
import org.apache.cordova.CallbackContext;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.apache.cordova.CordovaInterface;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.speech.tts.TextToSpeech;
|
||||
import android.speech.tts.TextToSpeech.OnInitListener;
|
||||
import android.speech.tts.UtteranceProgressListener;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
/*
|
||||
Cordova Text-to-Speech Plugin
|
||||
https://github.com/vilic/cordova-plugin-tts
|
||||
|
||||
by VILIC VANE
|
||||
https://github.com/vilic
|
||||
|
||||
MIT License
|
||||
*/
|
||||
|
||||
public class TTS extends CordovaPlugin implements OnInitListener {
|
||||
|
||||
public static final String ERR_INVALID_OPTIONS = "ERR_INVALID_OPTIONS";
|
||||
public static final String ERR_NOT_INITIALIZED = "ERR_NOT_INITIALIZED";
|
||||
public static final String ERR_ERROR_INITIALIZING = "ERR_ERROR_INITIALIZING";
|
||||
public static final String ERR_UNKNOWN = "ERR_UNKNOWN";
|
||||
|
||||
boolean ttsInitialized = false;
|
||||
TextToSpeech tts = null;
|
||||
|
||||
@Override
|
||||
public void initialize(CordovaInterface cordova, final CordovaWebView webView) {
|
||||
tts = new TextToSpeech(cordova.getActivity().getApplicationContext(), this);
|
||||
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
|
||||
@Override
|
||||
public void onStart(String s) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDone(String callbackId) {
|
||||
if (!callbackId.equals("")) {
|
||||
CallbackContext context = new CallbackContext(callbackId, webView);
|
||||
context.success();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String callbackId) {
|
||||
if (!callbackId.equals("")) {
|
||||
CallbackContext context = new CallbackContext(callbackId, webView);
|
||||
context.error(ERR_UNKNOWN);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext)
|
||||
throws JSONException {
|
||||
if (action.equals("speak")) {
|
||||
speak(args, callbackContext);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInit(int status) {
|
||||
if (status != TextToSpeech.SUCCESS) {
|
||||
tts = null;
|
||||
} else {
|
||||
// warm up the tts engine with an empty string
|
||||
HashMap<String, String> ttsParams = new HashMap<String, String>();
|
||||
ttsParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "");
|
||||
tts.setLanguage(new Locale("en", "US"));
|
||||
tts.speak("", TextToSpeech.QUEUE_FLUSH, ttsParams);
|
||||
|
||||
ttsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void speak(JSONArray args, CallbackContext callbackContext)
|
||||
throws JSONException, NullPointerException {
|
||||
JSONObject params = args.getJSONObject(0);
|
||||
|
||||
if (params == null) {
|
||||
callbackContext.error(ERR_INVALID_OPTIONS);
|
||||
return;
|
||||
}
|
||||
|
||||
String text;
|
||||
String locale;
|
||||
double rate;
|
||||
|
||||
if (params.isNull("text")) {
|
||||
callbackContext.error(ERR_INVALID_OPTIONS);
|
||||
return;
|
||||
} else {
|
||||
text = params.getString("text");
|
||||
}
|
||||
|
||||
if (params.isNull("locale")) {
|
||||
locale = "en-US";
|
||||
} else {
|
||||
locale = params.getString("locale");
|
||||
}
|
||||
|
||||
if (params.isNull("rate")) {
|
||||
rate = 1.0;
|
||||
} else {
|
||||
rate = params.getDouble("rate");
|
||||
}
|
||||
|
||||
if (tts == null) {
|
||||
callbackContext.error(ERR_ERROR_INITIALIZING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ttsInitialized) {
|
||||
callbackContext.error(ERR_NOT_INITIALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
HashMap<String, String> ttsParams = new HashMap<String, String>();
|
||||
ttsParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, callbackContext.getCallbackId());
|
||||
|
||||
String[] localeArgs = locale.split("-");
|
||||
tts.setLanguage(new Locale(localeArgs[0], localeArgs[1]));
|
||||
tts.setSpeechRate((float) rate);
|
||||
|
||||
tts.speak(text, TextToSpeech.QUEUE_FLUSH, ttsParams);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Cordova Text-to-Speech Plugin
|
||||
https://github.com/vilic/cordova-plugin-tts
|
||||
|
||||
by VILIC VANE
|
||||
https://github.com/vilic
|
||||
|
||||
MIT License
|
||||
*/
|
||||
|
||||
#import <Cordova/CDV.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
@interface CDVTTS : CDVPlugin <AVSpeechSynthesizerDelegate> {
|
||||
AVSpeechSynthesizer* synthesizer;
|
||||
NSString* lastCallbackId;
|
||||
NSString* callbackId;
|
||||
}
|
||||
|
||||
- (void)speak:(CDVInvokedUrlCommand*)command;
|
||||
@end
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Cordova Text-to-Speech Plugin
|
||||
https://github.com/vilic/cordova-plugin-tts
|
||||
|
||||
by VILIC VANE
|
||||
https://github.com/vilic
|
||||
|
||||
MIT License
|
||||
*/
|
||||
|
||||
#import <Cordova/CDV.h>
|
||||
#import "CDVTTS.h"
|
||||
|
||||
@implementation CDVTTS
|
||||
|
||||
- (void)pluginInitialize {
|
||||
synthesizer = [AVSpeechSynthesizer new];
|
||||
synthesizer.delegate = self;
|
||||
}
|
||||
|
||||
- (void)speechSynthesizer:(AVSpeechSynthesizer*)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance*)utterance {
|
||||
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||||
if (lastCallbackId) {
|
||||
[self.commandDelegate sendPluginResult:result callbackId:lastCallbackId];
|
||||
lastCallbackId = nil;
|
||||
} else {
|
||||
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
|
||||
callbackId = nil;
|
||||
}
|
||||
|
||||
[[AVAudioSession sharedInstance] setActive:NO withOptions:0 error:nil];
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient
|
||||
withOptions: 0 error: nil];
|
||||
[[AVAudioSession sharedInstance] setActive:YES withOptions: 0 error:nil];
|
||||
}
|
||||
|
||||
- (void)speak:(CDVInvokedUrlCommand*)command {
|
||||
[[AVAudioSession sharedInstance] setActive:NO withOptions:0 error:nil];
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
|
||||
withOptions:AVAudioSessionCategoryOptionDuckOthers error:nil];
|
||||
|
||||
if (callbackId) {
|
||||
lastCallbackId = callbackId;
|
||||
}
|
||||
|
||||
callbackId = command.callbackId;
|
||||
|
||||
[synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
|
||||
|
||||
NSDictionary* options = [command.arguments objectAtIndex:0];
|
||||
|
||||
NSString* text = [options objectForKey:@"text"];
|
||||
NSString* locale = [options objectForKey:@"locale"];
|
||||
double rate = [[options objectForKey:@"rate"] doubleValue];
|
||||
|
||||
if (!locale || (id)locale == [NSNull null]) {
|
||||
locale = @"en-US";
|
||||
}
|
||||
|
||||
if (!rate) {
|
||||
rate = 1.0;
|
||||
}
|
||||
|
||||
AVSpeechUtterance* utterance = [[AVSpeechUtterance new] initWithString:text];
|
||||
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:locale];
|
||||
// Rate expression adjusted manually for a closer match to other platform.
|
||||
utterance.rate = (AVSpeechUtteranceMinimumSpeechRate * 1.5 + AVSpeechUtteranceDefaultSpeechRate) / 2.5 * rate * rate;
|
||||
utterance.pitchMultiplier = 1.2;
|
||||
[synthesizer speakUtterance:utterance];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Cordova Text-to-Speech Plugin
|
||||
https://github.com/vilic/cordova-plugin-tts
|
||||
|
||||
by VILIC VANE
|
||||
https://github.com/vilic
|
||||
|
||||
MIT License
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Phone.Speech.Synthesis;
|
||||
using WPCordovaClassLib.Cordova;
|
||||
using WPCordovaClassLib.Cordova.Commands;
|
||||
using WPCordovaClassLib.Cordova.JSON;
|
||||
|
||||
namespace Cordova.Extension.Commands {
|
||||
[DataContract]
|
||||
class Options {
|
||||
[DataMember]
|
||||
public string text;
|
||||
[DataMember]
|
||||
public string locale;
|
||||
[DataMember]
|
||||
public double? rate;
|
||||
}
|
||||
|
||||
class TTS : BaseCommand {
|
||||
SpeechSynthesizer synth = new SpeechSynthesizer();
|
||||
|
||||
string lastCallbackId;
|
||||
|
||||
public async void speak(string argsJSON) {
|
||||
if (lastCallbackId != null) {
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.OK), lastCallbackId);
|
||||
lastCallbackId = null;
|
||||
synth.CancelAll();
|
||||
}
|
||||
|
||||
var args = JsonHelper.Deserialize<string[]>(argsJSON);
|
||||
var options = JsonHelper.Deserialize<Options>(args[0]);
|
||||
lastCallbackId = args[1];
|
||||
|
||||
var locale = options.locale != null ? options.locale : "en-US";
|
||||
var rate = options.rate != null ? options.rate : 1.0;
|
||||
|
||||
var ssml =
|
||||
@"<?xml version=""1.0""?>
|
||||
<speak version=""1.0""
|
||||
xmlns=""http://www.w3.org/2001/10/synthesis""
|
||||
xml:lang=""" + locale + @""">
|
||||
<prosody pitch=""x-high"" rate=""" + rate + @""">" + xmlEncode(options.text) + @"</prosody>
|
||||
</speak>";
|
||||
|
||||
try {
|
||||
await synth.SpeakSsmlAsync(ssml);
|
||||
lastCallbackId = null;
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
|
||||
} catch (OperationCanceledException) {
|
||||
// do nothing
|
||||
} catch (Exception e) {
|
||||
Debug.WriteLine(e.Message);
|
||||
lastCallbackId = null;
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
|
||||
}
|
||||
}
|
||||
|
||||
string xmlEncode(string text) {
|
||||
return text
|
||||
.Replace("&", "&")
|
||||
.Replace("<", "<")
|
||||
.Replace(">", ">");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user