Search Unity

Android Plugin unreliable

Discussion in 'Android' started by AiRobotMedia, Dec 12, 2018.

  1. AiRobotMedia

    AiRobotMedia

    Joined:
    Jun 13, 2018
    Posts:
    61
    Hi All,
    I have an app that uses the native text to speech api via a plugin. The problem with it is that it works 3 out of 10 times in a test app and less than that in my main app. I'm not really a java programmer thankfully.

    It is a little bit more reliable if I use speak, but I need a sound file so I am using synthesisToFile. I'm hoping someone can get the success rate up a bit.

    Here is the java code which i place in Assets > Plugins > Android folder and let gradle build it. I've tried a lot of things that don't work, which are commented out. UtteranceProgressListener never works no matter what I do.

    Code (CSharp):
    1. package ir.hoseinporazar.androidtts;
    2.  
    3. import android.content.Context;
    4. import android.os.Build;
    5. import android.os.Bundle;
    6. import android.speech.tts.TextToSpeech;
    7. import android.speech.tts.UtteranceProgressListener;
    8. import android.widget.Toast;
    9. import java.io.File;
    10. import java.util.HashMap;
    11. import java.util.Locale;
    12. import com.unity3d.player.UnityPlayer;
    13.  
    14.  
    15. public class TTS {
    16.     private Context context;
    17.     private TextToSpeech t1;
    18.     private String textToSpeak="hello";
    19.     private String filePath = "";
    20.     private static TTS instance;
    21.     public float Speed=1f;
    22.     public float Pitch=1f;
    23.  
    24.     private String _gameObject;
    25.     private String _completedCallback;
    26.     private String _errorCallback;
    27.  
    28.     public TTS() {
    29.         this.instance = this;
    30.     }
    31.  
    32.     public static TTS instance() {
    33.         if(instance == null) {
    34.             instance = new TTS();
    35.         }
    36.         return instance;
    37.     }
    38.  
    39.     public void setContext(Context context) {
    40.         this.context = context;
    41.     }
    42.  
    43.     public void showMessage(String message) {
    44.         Toast.makeText(this.context, message, Toast.LENGTH_SHORT).show();
    45.     }
    46.      String Error="";
    47.  
    48.     public void TTSFile(String text, String file, String gameobject, String errorCallback, String completedCallback) {
    49.         textToSpeak=text;
    50.         filePath = file;
    51.         this._gameObject=gameobject;
    52.         this._errorCallback=errorCallback;
    53.         this._completedCallback = completedCallback;
    54.         t1=new TextToSpeech(context, new TextToSpeech.OnInitListener() {
    55.             @Override
    56.             public void onInit(int status) {
    57.             if(status==TextToSpeech.SUCCESS){
    58.                 int result=t1.setLanguage(Locale.US);
    59.                 if(result==TextToSpeech.LANG_MISSING_DATA||result==TextToSpeech.LANG_NOT_SUPPORTED){
    60.                      Error="This language is not supported!";
    61.                 }
    62.              
    63.                 //}
    64.             }else{
    65.                  Error="TTS Initialization failed!";
    66.             }
    67.            }
    68.         });
    69.         //t1.setSpeechRate(Speed);
    70.        // t1.setPitch(Pitch);
    71.        t1.setOnUtteranceProgressListener(new UtteranceProgressListener() {
    72.                         @Override
    73.                         public void onStart(String s) {}
    74.  
    75.                         @Override
    76.                         public void onDone(String utteranceId) {   }
    77.  
    78.                         @Override
    79.                         public void onError(String s) { UnityPlayer.UnitySendMessage(_gameObject, _errorCallback, s); }
    80.                 });
    81.                 //if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){
    82.                 //    Bundle params = new Bundle();
    83.                 //    String utteranceId=this.hashCode() + "";
    84.                 //    File fileTTS = new File(filePath);
    85.                 //    t1.synthesizeToFile(textToSpeak, params, fileTTS, utteranceId);
    86.                 //}else{
    87.         HashMap<String, String> map = new HashMap<>();
    88.         map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "UniqueID");
    89.         int result = t1.synthesizeToFile(textToSpeak, map, filePath);
    90.         if(result == TextToSpeech.SUCCESS)
    91.         {
    92.             UnityPlayer.UnitySendMessage(_gameObject, _completedCallback, filePath);
    93.         }
    94.         else
    95.         {
    96.             UnityPlayer.UnitySendMessage(_gameObject, this._errorCallback, Error);
    97.         }
    98.     }
    99.  
    100.     public void SetLang(String loc){
    101.         switch (loc){
    102.             case "UK":
    103.                 if(t1!=null)
    104.                 t1.setLanguage(Locale.UK);
    105.                 break;
    106.             case "US":
    107.                 if(t1!=null)
    108.                 t1.setLanguage(Locale.US);
    109.                 break;
    110.         }
    111.     }
    112. }
    113.  
    Here is the text to speech csharp files that interacts with the java code. In the test project I just have a canvas and a button, with an onclick event that calls the speak method with a string.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using UnityEngine;
    5.  
    6. [RequireComponent(typeof(AudioSource))]
    7. public class TextToSpeech : MonoBehaviour
    8. {
    9.     AudioSource audioSource;
    10.  
    11.     private AndroidJavaObject TTSExample = null;
    12.     private AndroidJavaObject activityContext = null;
    13.     private Locale _lang;
    14.     public Locale Language { get { return _lang; } set { SetLanguage(value); } }
    15.     private float _pitch, _speed;
    16.     public float Pitch { get { return _pitch; } set { SetPitch(value); } }
    17.     public float Speed { get { return _speed; } set { SetSpeed(value); } }
    18.  
    19.     public delegate void OnErrorCallbackHandler(string error);
    20.     private OnErrorCallbackHandler _callback;
    21.  
    22.     List<string> filePaths = new List<string>();
    23.     int count = 5;
    24.     int index = 0;
    25.  
    26.     void Start()
    27.     {
    28.         audioSource = GetComponent<AudioSource>();
    29.  
    30.         if (Application.platform == RuntimePlatform.Android)
    31.         {
    32.             Initialize();
    33.         }
    34.  
    35.         filePaths.Add(Path.Combine(Application.persistentDataPath, "Temp0.wav"));
    36.         filePaths.Add(Path.Combine(Application.persistentDataPath, "Temp1.wav"));
    37.         filePaths.Add(Path.Combine(Application.persistentDataPath, "Temp2.wav"));
    38.         filePaths.Add(Path.Combine(Application.persistentDataPath, "Temp3.wav"));
    39.         filePaths.Add(Path.Combine(Application.persistentDataPath, "Temp4.wav"));
    40.     }
    41.  
    42.     public enum Locale
    43.     {
    44.         UK = 0,
    45.         US = 1
    46.     }
    47.  
    48.     public void Speak(string toSay)
    49.     {
    50.         if (!string.IsNullOrWhiteSpace(toSay))
    51.         {
    52.             // Round Robin of file paths to avoid collisions
    53.             SpeakToFile(toSay, filePaths[index % count]);
    54.  
    55.             index++;
    56.         }
    57.     }
    58.  
    59.     public void SpeakToFile(string toSay, string file)
    60.     {
    61.         if (TTSExample == null)
    62.         {
    63.             Initialize();
    64.         }
    65.  
    66.         TTSExample.Call("TTSFile", toSay, file, gameObject.name, "OnError", "OnCompleted");
    67.     }
    68.  
    69.     public void OnCompleted(string filePath)
    70.     {
    71.         StartCoroutine(LoadAudioFile(filePath));
    72.     }
    73.  
    74.     IEnumerator LoadAudioFile(string filePath)
    75.     {
    76.         yield return new WaitForSeconds(1);
    77.  
    78.         WWW www = new WWW("file:///" + filePath);
    79.         yield return www;
    80.  
    81.         audioSource.clip = www.GetAudioClip();
    82.         audioSource.Play();
    83.     }
    84.  
    85.     public void OnError(string error)
    86.     {
    87.         if (_callback != null)
    88.         {
    89.             if (error.Length > 0)
    90.             {
    91.                 _callback.Invoke(error);
    92.             }
    93.         }
    94.         ShowToast(error);
    95.     }
    96.  
    97.     public void SetLanguage(Locale lan)
    98.     {
    99.         this._lang = lan;
    100.         string[] Language = new string[] { "UK", "US" };
    101.         if (TTSExample == null)
    102.         {
    103.             Initialize();
    104.         }
    105.         TTSExample.Call("SetLang", Language[(int)lan]);
    106.     }
    107.  
    108.     public void SetSpeed(float speed)
    109.     {
    110.         this._speed = speed;
    111.         if (TTSExample == null)
    112.         {
    113.             Initialize();
    114.         }
    115.         TTSExample.Set<float>("Speed", speed);
    116.     }
    117.  
    118.     public void SetPitch(float pitch)
    119.     {
    120.         this._pitch = pitch;
    121.         if (TTSExample == null)
    122.         {
    123.             Initialize();
    124.         }
    125.         TTSExample.Set<float>("Pitch", pitch);
    126.     }
    127.  
    128.     private void Initialize()
    129.     {
    130.         if (TTSExample == null)
    131.         {
    132.             using (AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
    133.             {
    134.                 activityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");
    135.             }
    136.  
    137.             using (AndroidJavaClass pluginClass = new AndroidJavaClass("ir.hoseinporazar.androidtts.TTS"))
    138.             {
    139.                 if (pluginClass != null)
    140.                 {
    141.                     TTSExample = pluginClass.CallStatic<AndroidJavaObject>("instance");
    142.                     TTSExample.Call("setContext", activityContext);
    143.                 }
    144.             }
    145.         }
    146.     }
    147.  
    148.     public void ShowToast(string msg)
    149.     {
    150.         if (TTSExample == null)
    151.         {
    152.             using (AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
    153.             {
    154.                 activityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");
    155.             }
    156.  
    157.             using (AndroidJavaClass pluginClass = new AndroidJavaClass("ir.hoseinporazar.androidtts.TTS"))
    158.             {
    159.                 if (pluginClass != null)
    160.                 {
    161.                     TTSExample = pluginClass.CallStatic<AndroidJavaObject>("instance");
    162.                     TTSExample.Call("setContext", activityContext);
    163.                     activityContext.Call("runOnUiThread", new AndroidJavaRunnable(() =>
    164.                     {
    165.                         TTSExample.Call("showMessage", msg);
    166.                     }));
    167.                 }
    168.             }
    169.         }
    170.         else
    171.         {
    172.             activityContext.Call("runOnUiThread", new AndroidJavaRunnable(() =>
    173.             {
    174.                 TTSExample.Call("showMessage", msg);
    175.             }));
    176.         }
    177.     }
    178. }
    179.