1

On Android, I want to play TextToSpeech output through only one sound channel (think Shoulder Angel). To do this, I am currently using tts.synthesizeToFile(), and then playing back the dynamically-created file using the MediaPlayer. I use mediaPlayer.setVolume(0.0f, 1.0f) to play the audio through only one channel.

My working code is below.

My question is: is there a more direct way of playing TTS output through a single channel?

Using TextToSpeech to synthesize the file is time-consuming, and using MediaPlayer to play it back uses more resources than strictly necessary. I want this to be responsive and to work on low-end devices, so being kind to the CPU is important.


MainActivity.java

package com.example.pantts;

import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.speech.tts.TextToSpeech;
import android.os.Bundle;
import android.speech.tts.UtteranceProgressListener;
import android.util.Log;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Locale;


public class MainActivity extends Activity implements TextToSpeech.OnInitListener {

    private TextToSpeech tts;
    private String toSpeak = "Hello, right ear!";
    private static final String FILE_ID = "file";
    private HashMap<String, String> hashMap = new HashMap<String, String>();

    private String filename;
    private TextToSpeech tts;
    private MediaPlayer mediaPlayer;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        filename = getFilesDir() + "/" + "tts.wav";
        Log.d("LOG", "file: " + filename);
        // /data/data/com.example.pantts/files/tts.wav

        mediaPlayer = new MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

        tts = new TextToSpeech(this, this);
        tts.setOnUtteranceProgressListener(mProgressListener);
    }

    public void onInit(int status) {
        if (status == TextToSpeech.SUCCESS) {
            tts.setLanguage(Locale.UK);
            hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, FILE_ID);

            // Using deprecated call for API 20 and earlier
            tts.synthesizeToFile(toSpeak, hashMap, filename);
            Log.d("LOG", "synthesizeToFile queued");
        }
    }

    private UtteranceProgressListener mProgressListener = 
            new UtteranceProgressListener() {
        @Override
        public void onStart(String utteranceId) {
            Log.d("LOG", "synthesizeToFile onStart " + utteranceId);
        }

        @Override
        public void onError(String utteranceId) {
            Log.d("LOG", "synthesizeToFile onError " + utteranceId);
        }

        @Override
        public void onDone(String utteranceId) {
            if (utteranceId.equals(FILE_ID)) { // Thanks to Hoan Nguyen for correcting this
                Log.d("LOG", "synthesizeToFile onDone " + utteranceId);

                try {
                    File ttsFile = new File(filename);
                    FileInputStream inputStream = new FileInputStream(ttsFile);
                    FileDescriptor fileDescriptor = inputStream.getFD();
                    mediaPlayer.reset();
                    mediaPlayer.setDataSource(fileDescriptor);
                    inputStream.close();

                    mediaPlayer.prepare();
                    mediaPlayer.setVolume(0.0f, 1.0f); // right channel only
                    mediaPlayer.start();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    };
}
James Newton
  • 6,623
  • 8
  • 49
  • 113
  • How do you do `mediaPlayer.setVolume(0.0f, 1.0f)` after API 21? Thanks [this is my question](http://stackoverflow.com/questions/36904903/how-to-manipulate-audio-channels-volume-with-audiotrack-setvolume-after-api-21) – VMMF Apr 28 '16 at 18:18

1 Answers1

1

There is nothing wrong with the synthesize, it is the comparison that is wrong. It should be

if (utteranceId.equals(FILE_ID))
Hoan Nguyen
  • 18,033
  • 3
  • 50
  • 54