我正在 Android Studio 项目中运行 Google Cloud TTS。我的语音服务课程:
public class SpeechService {
private static final String TAG = SpeechService.class.getSimpleName();
private static final String ttsAPIUrl = "https://texttospeech.googleapis.com/v1/text:synthesize";
private static final String APIKey = "APIKEY"; // Replace with your API key
private boolean busy = false;
private MediaPlayer mediaPlayer;
private SpeechCallback speechCallback;
private static SpeechService instance;
public static SpeechService getInstance(Context context) {
if (instance == null) {
instance = new SpeechService(context);
}
return instance;
}
private Context context;
// Update the constructor to accept a Context instance
private SpeechService(Context context) {
this.context = context;
}
public void speak(String text, SpeechCallback callback) {
if (busy) {
Log.d(TAG, "Speech Service busy!");
return;
}
busy = true;
speechCallback = callback;
new TextToSpeechTask().execute(text);
}
private class TextToSpeechTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
String text = params[0];
try {
JSONObject postData = buildPostData(text);
String response = makePOSTRequest(ttsAPIUrl, postData.toString());
JSONObject jsonResponse = new JSONObject(response);
if (jsonResponse.has("audioContent")) {
String audioContent = jsonResponse.getString("audioContent");
byte[] audioData = Base64.decode(audioContent, Base64.DEFAULT);
playAudio(audioData);
} else {
Log.e(TAG, "Invalid response: " + jsonResponse.toString());
}
} catch (IOException | JSONException e) {
Log.e(TAG, "Error: " + e.getMessage());
}
return null;
}
@Override
protected void onPostExecute(String result) {
busy = false;
if (speechCallback != null) {
speechCallback.onSpeechComplete();
}
}
}
private JSONObject buildPostData(String text) throws JSONException {
JSONObject voiceParams = new JSONObject();
voiceParams.put("languageCode", "en-IN");
voiceParams.put("name", "en-IN-Neural2-D");
JSONObject params = new JSONObject();
params.put("input", new JSONObject().put("text", text));
params.put("voice", voiceParams);
params.put("audioConfig", new JSONObject().put("audioEncoding", "LINEAR16"));
return params;
}
private void playAudio(byte[] audioData) {
try {
releaseMediaPlayer();
// Save audio data to a temporary file
File tempFile = File.createTempFile("tempAudio", ".pcm", context.getCacheDir());
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(audioData);
fos.close();
mediaPlayer = new MediaPlayer();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build());
} else {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
// Set data source using the temporary file path
mediaPlayer.setDataSource(tempFile.getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
releaseMediaPlayer();
// Optionally, delete the temporary file after playback
tempFile.delete();
}
});
mediaPlayer.start();
} catch (IOException e) {
Log.e(TAG, "Error playing audio: " + e.getMessage());
}
}
private void releaseMediaPlayer() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
}
private String makePOSTRequest(String urlString, String postData) throws IOException {
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("X-Goog-Api-Key", APIKey);
urlConnection.setDoOutput(true);
DataOutputStream outputStream = new DataOutputStream(urlConnection.getOutputStream());
outputStream.write(postData.getBytes());
outputStream.flush();
outputStream.close();
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
response.append(line);
}
return response.toString();
} finally {
urlConnection.disconnect();
}
}
public interface SpeechCallback {
void onSpeechComplete();
}
}
当我在 MainActivity 中使用此类时:
String textToSpeak = "Hello," + username + ", How are you? Are you ready to play with me?";
speechService.speak(textToSpeak, new SpeechService.SpeechCallback() {
@Override
public void onSpeechComplete() {
// The first speech is complete, start the second one here
Log.w("SOUND", "Done with TTS");
}
});
甚至在演讲结束之前,它就会打印“Done with TTS”。我该如何解决这个问题?我希望能够根据用户活动嵌套多个文本转语音语句,但如果它们全部同时运行,这是不可能的,这就是现在正在发生的情况。
你应该做 busy = false;在音乐播放器的 onCompletion 中而不是在 onPostExecute
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
busy = false
releaseMediaPlayer();
// Optionally, delete the temporary file after playback
tempFile.delete();
} });