循环播放.wav文件,然后播放Android Text To Speech

时间:2019-01-24 11:44:49

标签: android text-to-speech

要求是在使用Android文字转语音功能后,在其后播放一个铃声。

for (final Integer orderId : voiceoverIds) {

    alertChimePlayer = MediaPlayer.create(getApplicationContext(), R.raw.orderalert);

    alertChimePlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        public void onCompletion(MediaPlayer mp) {
            String orderSpeechText = "Number " + orderId;
            textToSpeech.speak(orderSpeechText, TextToSpeech.QUEUE_ADD, null, "ORDER_NO_" + orderId);
            textToSpeech.playSilentUtterance(2000, TextToSpeech.QUEUE_ADD, "PAUSE_NO_" + orderId);

            System.out.println(">>>>>>>>>>>>>>>>>>> orderSpeechText : " + orderSpeechText);
        }   
    });

    alertChimePlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            alertChimePlayer.start();
        }
    });
}

但是这只能工作一次。如何正确处理呢?

2 个答案:

答案 0 :(得分:2)

好问题。整夜熬夜。问题在于,在循环中,这些提示音会很快同时全部发送到媒体播放器。 Media Player无法真正正确处理此问题。 这是我的解决方案。我正在使用SoundPool演奏提示音,因为它更适合重复播放短声音。 我还使用计时器线程来触发“铃音+语音合成语音(tts)”序列。 tts onUtteranceProgressListener用于在发出提示音后播放tts。 这是经过测试的代码。您将听到的是: 铃声“数字1”(延迟3秒) 铃声“数字2”(延迟3秒) ...继续直到终止

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

import java.util.Locale;

public class MainActivity extends Activity implements TextToSpeech.OnInitListener {

    AudioAttributes aa;
    SoundPool sp;
    private TextToSpeech tts;
    int MAX_STREAMS = 5;
    int REPEAT = 0;
    int DELAY = 3000;
    int orderId = 0;

    // Clock thread
    Thread m_clockThread;
    boolean m_bClockThreadStop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e("TTS", "Starting...");

        // Set up the sound pool sound
        AudioAttributes aa = new AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .build();

        sp = new SoundPool.Builder()
                .setMaxStreams(8)
                .setAudioAttributes(aa)
                .build();

        // Start the tts
        tts = new TextToSpeech(MainActivity.this,MainActivity.this);
        tts.setLanguage(Locale.US);
    }

    @Override
    public void onInit(int status) {
        Log.e("TTS", "Enter onInit...");
        if (status == TextToSpeech.SUCCESS) {
            int result = tts.setLanguage(Locale.US);
            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Log.e("TTS", "This Language is not supported");
            } else {
                Log.e("TTS", "onInit Success");
                // create and run clock thread
                createAndRunClockThread(this);
            }
        } else {
            Log.e("TTS", "onInit Fail");
        }
    }

    public void createAndRunClockThread(final Activity act) {
        m_bClockThreadStop=false;
        m_clockThread = new Thread(new Runnable() {
            public void run() {
                while(!m_bClockThreadStop) {
                    try {
                        act.runOnUiThread(new Runnable() {
                            public void run() {
                                playChime();
                            }
                        });
                        Thread.sleep(DELAY);
                    }
                    catch(InterruptedException e) {
                        Log.e("TTS", "ClockThread fail");
                    }
                }
            }
        });
        m_clockThread.start();
    }

    private void playChime() {
        Log.e("TTS", "Entering startChimes...");

        sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(final SoundPool soundPool, final int soundId, int status) {
                final int priority = 0;
                final int repeat = 0;
                final float rate = 1.f; // Frequency Rate can be from .5 to 2.0
                // Set volume
                AudioManager mgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
                float streamVolumeCurrent = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
                float streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
                final float volume = streamVolumeCurrent / streamVolumeMax;
                // Play a chime followed by the tts
                tts.speak("Number " + orderId, TextToSpeech.QUEUE_ADD, null, "ID" + orderId);
                tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
                    @Override
                    public void onStart(String utteranceId) {
                        // Speaking started.
                        sp.play(soundId, volume, volume, priority, repeat, rate);
                    }
                    @Override
                    public void onDone(String utteranceId) {
                        // Speaking stopped.
                        orderId = orderId + 1;
                    }
                    @Override
                    public void onError(String utteranceId) {
                        // There was an error.
                    }
                });
            }
        });
        sp.load(this, R.raw.beep, 1);
    }
}

答案 1 :(得分:0)

感谢@Mark W的回答。但是我正在考虑不涉及明显延迟/睡眠的解决方案。

所以我正在实现此服务类。

public class OrderNoticeService extends Service implements TextToSpeech.OnInitListener {
    private List<OrderSpeechAsyncTask> orderSpeechAsyncTasks = new ArrayList<>();
    private TextToSpeech textToSpeech;
    private Context context;

    public void addToOrderNoticeQueue(int orderId) {
        String orderSpeechText = String.format(getResources().getString(R.string.order_voice_over_default_text), Integer.toString(orderId));
        orderSpeechAsyncTasks.add(new OrderSpeechAsyncTask(getApplicationContext(), R.raw.orderalert, orderSpeechText, textToSpeech, new AsyncTaskCallback() {
            @Override
            public void onTaskCompleted(Object response) {
            }
        }));

        if (orderSpeechAsyncTasks.size() > 1) {
            final OrderSpeechAsyncTask orderSpeechAsyncTask = orderSpeechAsyncTasks.get(orderSpeechAsyncTasks.size() - 1);
            OrderSpeechAsyncTask orderSpeechAsyncTaskPrior = orderSpeechAsyncTasks.get(orderSpeechAsyncTasks.size() - 2);
            orderSpeechAsyncTaskPrior.setAsyncTaskCallback(new AsyncTaskCallback() {
                @Override
                public void onTaskCompleted(Object response) {
                    try {
                        orderSpeechAsyncTask.execute();
                        System.out.println("Execution!");
                    } catch (Exception e) {

                    }
                }
            });
        }
    }

    @Override
    public void onCreate() {
        textToSpeech = new TextToSpeech(this, this);
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        context = this;
        return Service.START_STICKY;
    }

    private static final String TAG = "OrderNoticeService";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "OrderNoticeService onBind");
        return mBinder;
    }

    @Override
    public void onDestroy() {
        if (textToSpeech != null) {
            textToSpeech.stop();
            textToSpeech.shutdown();
        }
        Log.i(TAG, "OrderNoticeService onDestroy");
    }

    @Override
    public void onInit(int status) {
        if (status == TextToSpeech.SUCCESS) {
            OrderNoticeVoiceOverThread orderNoticeVoiceOverThread = new OrderNoticeVoiceOverThread(context, orderSpeechAsyncTasks);
            orderNoticeVoiceOverThread.start();
        } else {
            System.out.println("Text To Speech not supported!");
        }
    }

    private class OrderNoticeVoiceOverThread extends Thread {
        private Context context;
        private List<OrderSpeechAsyncTask> orderSpeechAsyncTasks;
        private boolean anyTaskRunning = false;

        public OrderNoticeVoiceOverThread(Context context, List<OrderSpeechAsyncTask> orderSpeechAsyncTasks) {
            this.context = context;
            this.orderSpeechAsyncTasks = orderSpeechAsyncTasks;
        }

        public void run() {
            while (true) {

                for (OrderSpeechAsyncTask orderSpeechAsyncTask : new ArrayList<OrderSpeechAsyncTask>(orderSpeechAsyncTasks)) {
                    if (orderSpeechAsyncTask != null && orderSpeechAsyncTask.getStatus().equals(AsyncTask.Status.RUNNING)) {
                        anyTaskRunning = true;
                        break;
                    }
                }

                if (!anyTaskRunning) {
                    for (OrderSpeechAsyncTask orderSpeechAsyncTask : new ArrayList<OrderSpeechAsyncTask>(orderSpeechAsyncTasks)) {
                        if (orderSpeechAsyncTask != null && orderSpeechAsyncTask.getStatus().equals(AsyncTask.Status.PENDING)) {
                            orderSpeechAsyncTask.execute();
                            anyTaskRunning = false;
                            break;
                        }
                    }
                }
            }
        }
    }

    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        public OrderNoticeService getService() {
            return OrderNoticeService.this;
        }
    }
}

还有OrderSpeechAsyncTask

public class OrderSpeechAsyncTask extends AsyncTask<Void, Void, Void> {
    private static final String LOG_TAG = OrderSpeechAsyncTask.class.getSimpleName();
    private MediaPlayer mediaPlayer;
    private int soundId;
    private Context context;
    private String orderSpeechText;
    private AsyncTaskCallback asyncTaskCallback;
    private TextToSpeech textToSpeech;

    public OrderSpeechAsyncTask(final Context context, int soundId, String orderSpeechText, TextToSpeech textToSpeech, AsyncTaskCallback asyncTaskCallback) {
        this.context = context;
        this.soundId = soundId;
        this.orderSpeechText = orderSpeechText;
        this.textToSpeech = textToSpeech;
        this.asyncTaskCallback = asyncTaskCallback;
    }

    public AsyncTaskCallback getAsyncTaskCallback() {
        return asyncTaskCallback;
    }

    public void setAsyncTaskCallback(AsyncTaskCallback asyncTaskCallback) {
        this.asyncTaskCallback = asyncTaskCallback;
    }

    @Override
    protected Void doInBackground(Void... params) {
        mediaPlayer = MediaPlayer.create(context, soundId);
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                mediaPlayer.release();
                textToSpeech.speak(orderSpeechText, TextToSpeech.QUEUE_ADD, null, "ORDER_NO_" + orderSpeechText);
                textToSpeech.playSilentUtterance(2000, TextToSpeech.QUEUE_ADD, "PAUSE_NO_" + orderSpeechText);

                textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
                    @Override
                    public void onStart(String utteranceId) {

                    }

                    @Override
                    public void onDone(String utteranceId) {
                        asyncTaskCallback.onTaskCompleted(null);
                    }

                    @Override
                    public void onError(String utteranceId) {

                    }
                });
            }
        });
        mediaPlayer.start();

        return null;
    }
}

到目前为止,它可以处理以下内容;

  • 播放列表中的声音和文字
  • 在仍在读取现有列表的同时将项目添加到队列中

要做;

  • 读取完现有项目后,这不会处理添加到列表中的任何新项目。