TTS 不受 AudioManager 设置的音量影响
TTS not impacted by the volume set by the AudioManager
我在实施 TTS(文本转语音)应用程序时遇到问题。基本上,当我触发我的 Text To Speech 方法时,我试图用最大音量覆盖当前音量。我可以在 phone 上看到音量控制的变化,但它似乎不会影响 TTS 的音量,因为 TTS 音量保持不变。我无法找出确切的问题。
我依次调用的3个方法
setMaxVolume();
activateTTS(myString);
setDefaultVolume();
设置最大音量
private void setMaxVolume(){
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
}
激活TTS
private void activateTTS(String myString) {
if(androidAPILevel < 21){
HashMap<String, String> params = new HashMap<>();
params.put(TextToSpeech.Engine.KEY_PARAM_VOLUME, "1");
textToSpeech.speak(myString, TextToSpeech.QUEUE_FLUSH, params);
} else{
Bundle params = new Bundle();
params.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, 1f);
textToSpeech.speak(myString, TextToSpeech.QUEUE_FLUSH, params, null);
}
}
设置默认音量
private void setDefaultVolume(){
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);
}
目的是将音量控制权交给用户,而不是让 phone 音量影响 TTS 服务。
辅助求解的附加函数:
private TextToSpeech textToSpeech;
private int androidAPILevel = Build.VERSION.SDK_INT;
AudioManager audioManager;
int currentVolume;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
textToSpeech = new TextToSpeech(this,
this
);
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override
public void onStart(String s) {
}
@Override
public void onDone(String s) {
if (!getUserPreference().getTest()) {
Toast.makeText(TimeWhisperService.this, "TTS Finished", Toast.LENGTH_SHORT).show();
setDefaultVolume();
}
}
@Override
public void onError(String s) {
}
});
Log.v(TAG, "oncreate_service");
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
textToSpeech.setSpeechRate(Float.parseFloat(getUserPreference().getSpeed() + "f"));
textToSpeech.setPitch(Float.parseFloat(getUserPreference().getPitch() + "f"));
if(getUserPreference().getTest()) {
activateTTS(getMyString());
}
else{
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
setMaxVolume();
activateTTS(getMyString());
//setDefaultVolume();
}
}, 0, getUserPreference().getTimer() * 10000);
Log.v(TAG, "onstart_service");
}
super.onStart(intent, startId);
}
@Override
public void onInit(int status) {
Log.v(TAG, "oninit");
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(Locale.UK);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.v(TAG, "Language is not available.");
} else {
//textToSpeech.setOnUtteranceCompletedListener(this);
activateTTS(getMyString());
}
} else {
Log.v(TAG, "Could not initialize TextToSpeech.");
}
}
问题是您使用的是 "calling in sequence" 三种方法,但实际发生的是第三种方法被调用,将系统音量重置为正常...甚至在 TTS 开始说话之前。
原因是,根据 documentation,speak() 方法是异步的。
所以...解决此问题的方法是创建一个 UtteranceProgressListener 并将 setDefaultVolume() 方法移动到它的 onDone() 方法中。
旁注:为了调用任何 UtteranceProgressListener 回调,utteranceID 不能为 null...因此也进行了更改:
public class MainActivity extends AppCompatActivity {
int androidAPILevel = android.os.Build.VERSION.SDK_INT;
TextToSpeech textToSpeech;
AudioManager audioManager;
int currentVolume;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int i) {
start();
}
});
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override
public void onStart(String s) {
}
@Override
public void onDone(String s) {
Log.i("XXX", "onDone() called.");
setDefaultVolume(); // sets volume back to normal *after* speech is done.
}
@Override
public void onError(String s) {
Log.i("XXX", "onError() called.");
setDefaultVolume(); // sets volume back to normal *after* speech is done.
}
});
}
private void start() {
setMaxVolume();
activateTTS("hello! hello! hello! hello! hello! hello!");
}
private void activateTTS(String myString) {
if(androidAPILevel < 21){
HashMap<String, String> params = new HashMap<>();
params.put(TextToSpeech.Engine.KEY_PARAM_VOLUME, "1");
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "thisNeedsToBeSet");
textToSpeech.speak(myString, TextToSpeech.QUEUE_FLUSH, params);
} else{
Bundle params = new Bundle();
params.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, 1f);
textToSpeech.speak(myString, TextToSpeech.QUEUE_FLUSH, params, "thisNeedsToBeSet");
}
}
private void setMaxVolume(){
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
}
private void setDefaultVolume(){
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);
}
}
编辑:最好在 onError() 和 onDone() 回调中实现您想要的行为。据我所知,其中一个或另一个总是被称为。这样,如果出现错误,你的音量就不会卡在高位了。
我在实施 TTS(文本转语音)应用程序时遇到问题。基本上,当我触发我的 Text To Speech 方法时,我试图用最大音量覆盖当前音量。我可以在 phone 上看到音量控制的变化,但它似乎不会影响 TTS 的音量,因为 TTS 音量保持不变。我无法找出确切的问题。
我依次调用的3个方法
setMaxVolume();
activateTTS(myString);
setDefaultVolume();
设置最大音量
private void setMaxVolume(){
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
}
激活TTS
private void activateTTS(String myString) {
if(androidAPILevel < 21){
HashMap<String, String> params = new HashMap<>();
params.put(TextToSpeech.Engine.KEY_PARAM_VOLUME, "1");
textToSpeech.speak(myString, TextToSpeech.QUEUE_FLUSH, params);
} else{
Bundle params = new Bundle();
params.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, 1f);
textToSpeech.speak(myString, TextToSpeech.QUEUE_FLUSH, params, null);
}
}
设置默认音量
private void setDefaultVolume(){
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);
}
目的是将音量控制权交给用户,而不是让 phone 音量影响 TTS 服务。
辅助求解的附加函数:
private TextToSpeech textToSpeech;
private int androidAPILevel = Build.VERSION.SDK_INT;
AudioManager audioManager;
int currentVolume;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
textToSpeech = new TextToSpeech(this,
this
);
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override
public void onStart(String s) {
}
@Override
public void onDone(String s) {
if (!getUserPreference().getTest()) {
Toast.makeText(TimeWhisperService.this, "TTS Finished", Toast.LENGTH_SHORT).show();
setDefaultVolume();
}
}
@Override
public void onError(String s) {
}
});
Log.v(TAG, "oncreate_service");
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
textToSpeech.setSpeechRate(Float.parseFloat(getUserPreference().getSpeed() + "f"));
textToSpeech.setPitch(Float.parseFloat(getUserPreference().getPitch() + "f"));
if(getUserPreference().getTest()) {
activateTTS(getMyString());
}
else{
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
setMaxVolume();
activateTTS(getMyString());
//setDefaultVolume();
}
}, 0, getUserPreference().getTimer() * 10000);
Log.v(TAG, "onstart_service");
}
super.onStart(intent, startId);
}
@Override
public void onInit(int status) {
Log.v(TAG, "oninit");
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(Locale.UK);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.v(TAG, "Language is not available.");
} else {
//textToSpeech.setOnUtteranceCompletedListener(this);
activateTTS(getMyString());
}
} else {
Log.v(TAG, "Could not initialize TextToSpeech.");
}
}
问题是您使用的是 "calling in sequence" 三种方法,但实际发生的是第三种方法被调用,将系统音量重置为正常...甚至在 TTS 开始说话之前。
原因是,根据 documentation,speak() 方法是异步的。
所以...解决此问题的方法是创建一个 UtteranceProgressListener 并将 setDefaultVolume() 方法移动到它的 onDone() 方法中。
旁注:为了调用任何 UtteranceProgressListener 回调,utteranceID 不能为 null...因此也进行了更改:
public class MainActivity extends AppCompatActivity {
int androidAPILevel = android.os.Build.VERSION.SDK_INT;
TextToSpeech textToSpeech;
AudioManager audioManager;
int currentVolume;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int i) {
start();
}
});
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override
public void onStart(String s) {
}
@Override
public void onDone(String s) {
Log.i("XXX", "onDone() called.");
setDefaultVolume(); // sets volume back to normal *after* speech is done.
}
@Override
public void onError(String s) {
Log.i("XXX", "onError() called.");
setDefaultVolume(); // sets volume back to normal *after* speech is done.
}
});
}
private void start() {
setMaxVolume();
activateTTS("hello! hello! hello! hello! hello! hello!");
}
private void activateTTS(String myString) {
if(androidAPILevel < 21){
HashMap<String, String> params = new HashMap<>();
params.put(TextToSpeech.Engine.KEY_PARAM_VOLUME, "1");
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "thisNeedsToBeSet");
textToSpeech.speak(myString, TextToSpeech.QUEUE_FLUSH, params);
} else{
Bundle params = new Bundle();
params.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, 1f);
textToSpeech.speak(myString, TextToSpeech.QUEUE_FLUSH, params, "thisNeedsToBeSet");
}
}
private void setMaxVolume(){
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
}
private void setDefaultVolume(){
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);
}
}
编辑:最好在 onError() 和 onDone() 回调中实现您想要的行为。据我所知,其中一个或另一个总是被称为。这样,如果出现错误,你的音量就不会卡在高位了。