4

I have an app which is using TTS to read text in an AsyncTask. My problem is when the phone goes to sleep the playback stops. I went through many threads in the topic and everything points towards WakeLock. However I am not able to implement it, no matter if I call it in the activity class or the AsyncTask class. I use the following code:

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My wakelook");
wakeLock.acquire(1000);

I guess the problem is with TTS, but currently I am clueless. Maybe someone with more TTS and WakeLock experience could help me out.

Thanks in advance

EDIT:

Here is the full code (unimportant parts removed):

    public class PlayerActivity extends Activity implements
        TextToSpeech.OnInitListener {

    // TTS fields
    private TextToSpeech mTts;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.player);

        List<TTSPlayItem> playItems = new ArrayList<TTSPlayItem>();


        TTSPlayItem playItem = new TTSPlayItem();
        playItem.locale = getLocale1();
        playItem.text = getText1();
        playItem.position = position;
        playItems.add(playItem);
        playItem = new TTSPlayItem();
        playItem.locale = getLocale2();
        playItem.text = getText2();
        playItem.position = position;
        playItems.add(playItem);

        TTSPlayItem[] passPlayItems = playItems
                .toArray(new TTSPlayItem[playItems.size()]);
        TTSAsyncTask speak = new TTSAsyncTask();
        speak.execute(passPlayItems);
    }

    /*
     * AsyncTask for TTS
     */

    private class TTSAsyncTask extends
            AsyncTask<TTSPlayItem, TTSPlayItem, String> {

        // WakeLock
        PowerManager pm;
        PowerManager.WakeLock wakeLock;

        protected void onPreExecute() {
        }

        @Override
        protected String doInBackground(TTSPlayItem... items) {
            pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My wakelook");

            wakeLock.acquire();

            for (int i = 0; i < items.length; i++) {
                TTSPlayItem[] progressList = new TTSPlayItem[1];
                progressList[0] = items[i];
                publishProgress(progressList);
                Log.i(TAG, "Play - locale: " + items[i].locale.toString()
                        + ", text: " + items[i].text);

                int treshold = 0;
                while (true) {
                    int result = mTts.setLanguage(items[i].locale);
                    Log.i(TAG, "Locale return: " + result);
                    if (result == 1)
                        break;
                    if (treshold == 100)
                        break;
                    treshold++;
                }

                mTts.speak(items[i].text, TextToSpeech.QUEUE_FLUSH, null);
                while (mTts.isSpeaking()) {
                    if (playing == false) {
                        mTts.stop();
                        return "Playback stopped.";
                    }
                }

                // wait
                android.os.SystemClock.sleep(1000);
            }
            playing = false;

            if (wakeLock.isHeld())
                    wakeLock.release();

            return "Played list of " + items.length + " items.";
        }

        protected void onProgressUpdate(TTSPlayItem... result) {
        }

        protected void onPostExecute(String result) {
    }

    /*
     * TTS methods
     */

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == MY_DATA_CHECK_CODE) {
            if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
                // success, create the TTS instance
                mTts = new TextToSpeech(this, this);
            } else {
                // missing data, install it
                Intent installIntent = new Intent();
                installIntent
                        .setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                startActivity(installIntent);
            }
        }
    }

    public void shutdownTTS() {
        playing = false;
        // Don't forget to shutdown!
        if (mTts != null) {
            mTts.stop();
            mTts.shutdown();
        }
    }

    @Override
    public void onDestroy() {
        shutdownTTS();
        super.onDestroy();
    }

    public void onStop() {
        shutdownTTS();
        super.onStop();
    }

    public void onPause() {
        shutdownTTS();
        super.onPause();
    }
}
Sandor Farkas
  • 153
  • 2
  • 11
  • `wakeLock.acquire(1000)` acquires a wake lock that will last only 1000 milliseconds (1 second), that's too short a time for what you want, isn't it? You should `wakeLock.acquire()` (no timeout defined) and `wakeLock.release()` when the TTS finishes. – Piovezan Oct 30 '13 at 11:00
  • I thought it will waith that much time before aquiring the lock. let me check, thank you! – Sandor Farkas Oct 30 '13 at 11:12
  • I removed 1000, but still have the issue. It seems, that my application is running (as I see activity in the logs), but TTS stops working. – Sandor Farkas Oct 30 '13 at 11:14
  • Please post the full source code so we can have the proper context. – Piovezan Oct 30 '13 at 11:22
  • Added the code above, removed the unimportant parts. – Sandor Farkas Oct 30 '13 at 11:36
  • Where do you declare `playing` ? Are you initializing it with `false` ? Does it change somewhere else outside the code you provided? – Piovezan Oct 30 '13 at 11:43
  • Yes, that is just for other parts of the code. As it is a quite complex application I removed unimportant parts, but haven't checked everything. The important is that it is the structure I am using. Calling AsyncTask which launches TTS, which stops on screen lock. :( – Sandor Farkas Oct 30 '13 at 12:24
  • What I'm worried about is that `playing` may be already `false` when the app reaches the part `while (mTts.isSpeaking())` causing the while to leave immediately. Otherwise the code seems okay. I would just put the wakelock release code inside a finally `block` with the corresponding `try` block occupying the whole `doInBackground` method so you can perform `return` without leaving the wakelock unreleased. – Piovezan Oct 30 '13 at 12:37
  • One last check: Have you included the permission `android.permission.WAKE_LOCK` in your AndroidManifest.xml ? – Piovezan Oct 30 '13 at 12:58
  • Sorry, i forgot to mention that. Yes, I did – Sandor Farkas Oct 30 '13 at 13:03
  • Regarding playing variable: the purpose of it is to follow whether my player is running or stopped. So if a text is played via TTS it is checking this variable continuously, and if it is false, then it stops TTS. The code which handles this part is excluded from my example code above. – Sandor Farkas Oct 30 '13 at 13:10
  • 2
    Oh, I see what might be going on. `onPause()` is being called when the screen goes off and it causes the TTS to stop. Also as a side note, if you want TTS to work throughout more than one activity you should declare `mTts` outside the activity scope as it will be destroyed along with the activity when you change activities. – Piovezan Oct 30 '13 at 13:14
  • Piovezan: you are brilliant. This was the problem, I don't even need WakeLock, now my app works like a charm. :) THANK YOU! :D (Oh, and if you could add your comment as an answer, I'd love to accept it ;) – Sandor Farkas Oct 30 '13 at 13:30
  • Great. However I think you are going to need the wakelock if your TTS proceeds too long after the screen goes blank as the CPU usually enters sleep mode by that time. – Piovezan Oct 30 '13 at 13:34

1 Answers1

3

onPause() is being called when the screen goes off and it causes the TTS to stop.

Piovezan
  • 3,215
  • 1
  • 28
  • 45