java - TTS 不受 AudioManager 设置的音量影响

标签 java android android-studio text-to-speech android-audiomanager

我在实现 TTS(文本转语音)应用程序时遇到问题。基本上,当我触发“文本转语音”方法时,我试图用最大音量覆盖当前音量。我可以看到手机上音量控制的变化,但它似乎不会影响 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);
}

目的是把音量控制权交给用户,不让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.");
    }
}

最佳答案

问题是您“按顺序调用”三个方法,但实际发生的是调用第三个方法,将系统音量重置回正常状态...在 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() 回调中实现您想要的行为是一个好主意。据我所知,总是会调用其中之一。这样,如果出现错误,您的音量就不会卡在高位置。

关于java - TTS 不受 AudioManager 设置的音量影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52596513/

相关文章:

java.lang.ClassNotFoundException : sun. misc.Cleaner

java - 文件类错误 -

java - 将值分配给Map(Hashmap或Multimap)

android - 连接到 AND UA651BLE 时获取状态为 133 的 Type_Gatt_Error

java - Java中的正则表达式命名组

android - xml 文件中 View 的“类”属性

java - 没有 public RealmResults<E> 构造函数?

android - Gridview如何设计成守护神app

java - 无法解决 android studio 中的符号 'java.time.LocalDate' 错误

gradle - 在本地和另一个项目中构建 Studio/Gradle 项目