I have an app for people with low vision that relies heavily on TTS. However for some reason when I use the speak method TTS randomly skips the first few letters of a sentence or speaks the first few letters in a ver low volume and the rest in a normal volume.
Any idea why this might happen?
This is my current code:
public class SpeechHelper implements TextToSpeech.OnInitListener {
private Context context = null;
private TextToSpeech tts;
public SpeechHelper(Context context)
{
this.context = context;
try {
tts = new TextToSpeech(context, this);
} catch(Exception e) {
Log.e("Phone Features Exception","Couldn't initiate TTS", e);
}
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
tts.setLanguage(Locale.getDefault());
}
}
public void speak(String s, int mode, String messageID) {
Log.d("VOLUME", "getStreamVolume " + am.getStreamVolume(AudioManager.STREAM_MUSIC)); // Always 15
Log.d("VOLUME", "isMusicActive " + (am.isMusicActive() ? "true" : "false")); // Always false
Log.d("VOLUME", "isVolumeFixed " + (am.isVolumeFixed() ? "true" : "false")); // Always false
Log.d("VOLUME", "isSpeakerphoneOn: " + (am.isSpeakerphoneOn() ? "true" : "false")); // Always false
Log.d("VOLUME", "getMode: " + am.getMode()); // Always 0
HashMap<String, String> params = new HashMap<String, String>();
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, messageID);
tts.speak(s, mode, params);
}
}
I've noticed the problem always happens on the next 5 seconds after making a call or when unlocking the phone to the app.
Either you are doing something wrong or Android is doing something wrong. If I had to put money on it I would say it is you.
Start by just calling
tts.speak("the quick brown fox jumps over the lazy dog", tts.QUEUE_FLUSH, null);
to see if you can reproduce the problem in a test app (I couldn't). If you can, then I'd be very curious as to what phone/OS you are running on . Your problem probably lies with truncated strings, or something else programmatically messing with volume.
Related
I'm getting errors when trying to get a player's scores across all leaderboards, in order to store locally.
My Android game is designed to be played offline, so I store high score and lifetime scores locally for each game mode.
Now I am working on adding leaderboards to my game. During the game play, I periodically post these scores to the leaderboards. So far so good.
Naturally, I need to cover the scenario where a user either uninstalls my game or moves to a new device, etc. In that scenario, when they sign in again to Google, I need to update the scores that are on leaderboards back into my local version.
Here's where I seem to get 26504 - NETWORK_ERROR_NO_DATA when I make the 4th call.
I have tried to wait until the 3rd call is complete and then fire the 4th one but I still get the same error. So I haven't even been able to add code for the 5-6 additional scores I will still need to retrieve.
getScoresFromLeaderboards(GAME_MODE_FIXED_QUESTIONS, SCORE_HIGH);
getScoresFromLeaderboards(GAME_MODE_FIXED_QUESTIONS, SCORE_LIFETIME);
getScoresFromLeaderboards(GAME_MODE_RAPID_FIRE, SCORE_HIGH);
getScoresFromLeaderboards(GAME_MODE_RAPID_FIRE, SCORE_LIFETIME);
Then...
public long getScoresFromLeaderboards(final String gameMode, final String scoreType) {
final int scoreHigh = 0, scoreLifetime = 0;
String leaderboardID = getLeaderboardForGameMode(gameMode, scoreType);
mLeaderboardsClient.loadCurrentPlayerLeaderboardScore(leaderboardID, LeaderboardVariant.TIME_SPAN_ALL_TIME, LeaderboardVariant.COLLECTION_PUBLIC )
.addOnCompleteListener(new OnCompleteListener<AnnotatedData<LeaderboardScore>>() {
#Override
public void onComplete(#NonNull Task<AnnotatedData<LeaderboardScore>> task) {
if (task.isSuccessful()) {
AnnotatedData<LeaderboardScore> lbs = task.getResult();
long i = lbs.get().getRawScore();
// Do something to store the score locally
}
else{
Log.Error("Error", "Retrieval failed");
}
}
I would suggest another approach to using "loadCurrentPlayerLeaderboardScore" which has the 3 query limit
Use loadPlayerCenteredScores instead . Limit the scores to 1. The resultant buffer will return only the player score. You are now in the user quota of 500 requests instead of 3.
long limitResultsTo = 1;
String PlayerID = "-1"; // set this from playersClient.getCurrentPlayer() ->task-> getPlayerId()
String leaderboardID = getString(R.string.leaderboard_name); // or string of ID
Games.getLeaderboardsClient(this, GoogleSignIn.getLastSignedInAccount(this))
.loadPlayerCenteredScores(leaderboardName, LeaderboardVariant.TIME_SPAN_ALL_TIME, LeaderboardVariant.COLLECTION_PUBLIC, limitResultsTo)
.addOnSuccessListener(new OnSuccessListener<AnnotatedData<LeaderboardsClient.LeaderboardScores>>() {
#Override
public void onSuccess(AnnotatedData<LeaderboardsClient.LeaderboardScores> leaderboardScoreAnnotatedData) { // big ups Danoli3.com for the fix for loadCurrentPlayerLeaderboardScore
LeaderboardsClient.LeaderboardScores scoresResult = leaderboardScoreAnnotatedData.get();
LeaderboardScore scoreResult = (scoresResult != null ? scoresResult.getScores().get(0) : null);
long score = 0;
if(scoreResult != null && scoreResult.getScoreHolder() != null &&
PlayerID.equals(scoreResult.getScoreHolder().getPlayerId())) // else if the player has 0 score it will retrieve top player
score = scoreResult.getRawScore();
// use the score in your own code here
// Log.i(TAG, "loadPlayerCenteredScores:" + leaderboardID + " score:" + score);
leaderboardScoreAnnotatedData = null;
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "Failure:loadPlayerCenteredScores GPG:Leader:" + leaderboardID + " Ex:" + e.getMessage());
}
Okay so I made module for searching medicines and display items in a listview, I am using JDBC here. The main issue is when I place an underscore_ in the searchview, It kind of makes a bug where the listview items duplicate themselves.
Based on my observation; this bug only occurs when the underscore is inserted simultaneously, but if pressed at slower interval, It doesn't duplicate items anyway.
Here is what it looks without anything on the SearchView:
This is when underscores are placed at slower interval
And even if underscores doesn't exist in the listview it still displays it, but when I add even more underscores, they started to disappear one by one starting from the bottom.
And here's the main problem; when Underscores are placed simultaneously
Here are my code for the search in AsyncTask
private class searchUnfiltered extends AsyncTask<String, String, String> {
String z = "";
String fromSearchView = sv.getQuery().toString().trim();
boolean isSuccess = false;
String about;
#Override
protected void onPreExecute() {
myArrayList2.clear();
myArrayList.clear();
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
try {
Connection con = connectionClass.CONN();
if (con == null) {
z = "Please check your internet connection";
} else {
String querySearch = "select name from medicines where name like '%"+ fromSearchView +"%' order by name ASC";
Statement stmt1 = con.createStatement();
ResultSet rs1 = stmt1.executeQuery(querySearch);
if(rs1 != null) {
while (rs1.next()) {
myArrayList2.add(rs1.getString("name"));
}
}
}
} catch (Exception ex) {
isSuccess = false;
z = "Exceptions" + ex;
}
return z;
}
#Override
protected void onPostExecute(String s) {
if(!isSuccess && !z.equals("")) {
Toast.makeText(getBaseContext(), z, Toast.LENGTH_LONG).show();
}
ListAdapter listAdapter = new ArrayAdapter<>(MedicineSearch.this, android.R.layout.simple_list_item_1, myArrayList2);
lv.setAdapter(listAdapter);
}
}
Whenever value is changed in search view the searchUnfiltered will be triggered, please tell me if what I'm doing is efficient or if you have any better suggestions, it would be very helpful.
That is a race condition reason you are clearing the data onPreExecute then doInBackground is working typing 5 _ at a fast pace will clear 5 times before you get any results back.
as a Solution move:
myArrayList2.clear();// if this didn't work try myArrayList2 = new ArrayList<>();
from onPreExecute to doInBackground.
The thing that bugs me the most about this is; I have another activity that uses a different approach (using startActivityForResult(intent....) vs a listener class implementing RecognitionListener, and one works the other doesnt'. I'm certain I'm doing something stupidly wrong, but I sure can't figure out what.
I'm getting the speech recog results back using onResults, using a listener class that implements RecognitionListener.
public void onResults(Bundle results) {
Log.d("Speech", "onResults");
ArrayList strlist = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
for (int i = 0; i < strlist.size(); i++) {
String matchstring = matchpair[1].toString().toLowerCase();
String speechstring = strlist.get(i).toString().toLowerCase();
Log.d("Speech", "result=" + speechstring);
if (checkResult(matchstring, speechstring)) {
System.out.println("Phonetic match: " + speechstring + " = " + matchstring);
} else System.out.println("NO match: " + speechstring + " = " + matchstring);
}
}
The checkresult is simple, just a boolean compare:
public boolean checkResult(String result, String checkmatch) {
if (result.equals(checkmatch))
{
return true;
}
return false;
}
Looking at the debug info, the results appear to compare - but the boolean is returning false.
It's driving me nuts. I'm going this route so I can use the recognition functionality without having the Google dialog pop on every recognition attempt. In the activity I began with, the compare is working perfectly.
I welcome someone pointing out whatever very stupid thing I am overlooking.
I am using TextToSpeech to play some long texts sometimes, and I have noticed that since Android 4.1.2 if the text is longer than 4000 chars, it does not play.
I do not get any errors, but the text won't be played. Until now I was able to reproduce this just on Android 4.1.2(Samsung Galaxy Nexus, Nexus7).
Is this a bug just in 4.1.2 or is this normal (although I did not find any documentation regarding this behaviour)?
Also I have found a post : onUtteranceCompleted() lost if TTS received is too long which indicates different problems with texts longer than 4000 chars.
EDIT: I tried to split my string in 4k length chunks, and send it to TTS using QUEUE_ADD and I came across another bug: QUEUE_ADD does not work, instead it flushes the existing queue, and only the last chunk gets played.
EDIT2 : this is my call to TTS
mTTS.speak(longText, TextToSpeech.QUEUE_FLUSH, null);
MAX_SPEECH_ITEM_CHAR_LENGTH = 4000 in TtsService.java, on 4.1 I see a warn in the code:
#Override
public boolean isValid() {
if (mText == null) {
Log.wtf(TAG, "Got null text");
return false;
}
if (mText.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH) {
Log.w(TAG, "Text too long: " + mText.length() + " chars");
return false;
}
return true;
}
looks like 2.3 splits the text instead, so teorically your code should work on android < 4.1 and not on newer (I don't known when the split was removed), instead you have the opposite :) that is a bit strange
My solution was to use onUtteranceCompleted(String utteranceId) to know when the first chunk has finished, and then, feed the next chunk to TextToSpeech until they are all finished.
#Override
public void onInit(int status) { //On TTS init
//guava Splitter
mChunks=Lists.newLinkedList(Splitter.fixedLength(3999).split(mExtractedText));
mTTS.setOnUtteranceCompletedListener(this);
playNextChunk();
}
private void playNextChunk(){
HashMap<String, String> params = new HashMap<String, String>();
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, ""+mChunks.size());
mTTS.speak(mChunks.poll(), TextToSpeech.QUEUE_FLUSH, params);
}
#Override
public void onUtteranceCompleted(String utteranceId) {
playNextChunk();
}
No problem on 4.4.2... I split my Strings like this...
//textToSpeech can only cope with Strings with < 4000 characters
int dividerLimit = 3900;
if(textForReading.length() >= dividerLimit) {
int textLength = textForReading.length();
ArrayList<String> texts = new ArrayList<String>();
int count = textLength / dividerLimit + ((textLength % dividerLimit == 0) ? 0 : 1);
int start = 0;
int end = textForReading.indexOf(" ", dividerLimit);
for(int i = 1; i<=count; i++) {
texts.add(textForReading.substring(start, end));
start = end;
if((start + dividerLimit) < textLength) {
end = textForReading.indexOf(" ", start + dividerLimit);
} else {
end = textLength;
}
}
for(int i=0; i<texts.size(); i++) {
textToSpeech.speak(texts.get(i), TextToSpeech.QUEUE_ADD, null);
}
} else {
textToSpeech.speak(textForReading, TextToSpeech.QUEUE_FLUSH, null);
}
My problem is that I had a program working before, without threading, and it took a long time to process info (16 seconds to get XML data and display it). Now I've gotten the whole threading and async thing down, but for some reason it is making my program SLOWER (in the emulator, device is not available right now), is there anything I've done that could have caused this, the UI thread is fine, but my async thread takes a minute and a half to execute. (when I had it in the UI thread used to take only 16 seconds, but froze the UI thread)
Here is the code for my thread, it sits inside of the main class:
private class TeamSearchTask extends AsyncTask<String,Void,String> {
CharSequence nfo;
String [] matches;
String [] data;
String teamNum;
ProgressDialog loading;
protected void onPreExecute()
{
//Show the 'loading' dialog
loading = new ProgressDialog(SapphireAlliance.this);
loading.setMessage("Loading, please wait...");
loading.show();
}
protected String doInBackground(String... teamNumber)
{
try
{
//Team information ------------------------------------------------------------------------------------
teamNum = teamNumber[0];
//Array of team data
data = APIconnection.getTeams(teamNum, "");
//Display basic team info
nfo = ("\nFormal Team Name:\n" + data[1] +
"\n\nLocation:\n" + data [3] + ", " + data[4] + ", " + data[5] +
"\n\nRookie Year:\n" + data[6] +
"\n\nRobot Name:\n" + data[7] +
"\n\nWebsite:\n" + data[8] + "\n\n\n\n\n\n\n\n\n");
//Make match archive --------------------------------------------------------------------------------------
String [] events = APIconnection.getEventIdsByYear(year1);
ArrayList<String> matches = new ArrayList<String>();
for (int i = 0; i<events.length; i++)
{
String [] add = APIconnection.getMatches2(teamNum, events[i] ,"","");
for(int j = 0; j<add.length; j++)
matches.add(add[j]);
}
String [] out = new String [matches.size()];
matches.toArray(out);
return "";
}
catch(Exception e)
{
return e.toString();
}
}
protected void onPostExecute(String result) {
if(result.equals(""))
{
info.setText(nfo);
matchArchive(matches);
//title
CharSequence ttl = "Team " + teamNum;
titlets.setText(ttl.toString());
loading.dismiss();
}
else
{
alert.setMessage(result);
alert.show();
}
}
}
Anything in there that could be causing this? :|
It may be that your thread priority may not be set very high. I remember the default is rather low. However, for what you're doing, it shouldn't be taking more than a couple seconds. I would think that the real problem lies in APIconnection going to the network and doing something that takes a long time. Particularly, that for loop that does the event fetching would be doing a lot of work if each call opens a new socket, assuming that this is for FIRST matches. :P
I am having the same issue, doing nothing more than a file copy with simple DES decryption... the whole thing ran in a few seconds on the UI thread, but when moved into an ASYNCTASK it is now taking MINUTES to accomplish. Unbelievable.