title: How can I make TextToSpeech to speak a text with max volume and restore original volume after speak end?
body: <p>I save the current volume both <code>STREAM_RING</code> and  <code>STREAM_MUSIC</code> before <code>sTts.get().speak(s, TextToSpeech.QUEUE_ADD, null)</code>, I hope the <code>TextToSpeech</code> can speak a text with max volume,
  but in fact I find the <code>TextToSpeech</code> speak the text with current volume, it seems that <code>sTts.get().speak</code> is asynchronous.</p>
  
  <p>How can I make <code>TextToSpeech</code> to speak a text with max volume and restore original volume after speak end? Thanks!</p>
  
  <pre><code>public class SpeechTxt {
  private static SoftReference&lt;TextToSpeech&gt; sTts;
  
  public static void SpeakOut(final Context context, final String s) {
      final Context appContext = context.getApplicationContext();
      if (sTts == null) {
          sTts = new SoftReference&lt;TextToSpeech&gt;(new TextToSpeech(appContext,
                  new TextToSpeech.OnInitListener() {
                      @Override
                      public void onInit(int status) {
                          if (status == TextToSpeech.SUCCESS) {
                              speak(appContext, s);
                          } else {                                
                          }
                      }
                  }));
      } else {
          speak(appContext, s);
      }
  }
  
  private static void speak(Context context, String s) {
      if (sTts != null) {
          switch (sTts.get().setLanguage(Locale.getDefault())) {
          case TextToSpeech.LANG_COUNTRY_AVAILABLE:
          case TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE:
          case TextToSpeech.LANG_AVAILABLE: {
  
              sTts.get().setPitch((float) 0.6);
              sTts.get().setSpeechRate((float) 0.8);
  
              int currentRing=PublicParFun.GetCurrentVol(context, AudioManager.STREAM_RING);
              int currentPlay=PublicParFun.GetCurrentVol(context, AudioManager.STREAM_MUSIC);
  
              PublicParFun.SetRingVol(context, 0);
              PublicParFun.SetPlayVol(context,1000000);
  
                      sTts.get().speak(s, TextToSpeech.QUEUE_ADD, null);
  
              PublicParFun.SetRingVol(context, currentRing);
              PublicParFun.SetPlayVol(context,currentPlay);
  
              break;
          }
          case TextToSpeech.LANG_MISSING_DATA: {
  
              break;
          }
          case TextToSpeech.LANG_NOT_SUPPORTED: // not much to do here
          }
      }
  }
  
  
  public static int GetCurrentVol(Context myContext,int streamType){
      AudioManager mAudioManager = (AudioManager)myContext.getSystemService(Context.AUDIO_SERVICE);
      int current = mAudioManager.getStreamVolume( streamType);   
      return current;
  }   
  
  public static void SetRingVol(Context myContext,int vol){       
      SetVol(myContext,AudioManager.STREAM_RING, vol);
  }
  
  
  public static void SetPlayVol(Context myContext,int vol){
      SetVol(myContext,AudioManager.STREAM_MUSIC, vol);
  }
  
  private static void SetVol(Context myContext,int streamType,int vol){
      AudioManager mAudioManager = (AudioManager)myContext.getSystemService(Context.AUDIO_SERVICE);
      int max = mAudioManager.getStreamMaxVolume(streamType);
      if (vol&gt;max){
          vol=max;
      }
      mAudioManager.setStreamVolume(streamType,vol, 0);
  }
  </code></pre>
  
  <p>}</p>
  
  <p><strong>Edit</strong></p>
  
  <ol>
  <li><p>Is the following code right? I fixed my original code by your thinking.</p></li>
  <li><p>I can't understand why the code need to add HashMap, I think <code>sTts.get().setOnUtteranceProgressListener</code> and <code>sTts.get().setOnUtteranceCompletedListener</code> don't need HashMap, right?</p>
  
  <p>HashMap ttsParameters = new HashMap();
  ttsParameters.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"stringId");</p></li>
  </ol>
  
  <p>package bll;<br>
  public class SpeechTxt {
      private static SoftReference sTts;</p>
  
  <pre><code>public static void SpeakOut(final Context context, final String s) {
      final Context appContext = context.getApplicationContext();
      if (sTts == null) {
          sTts = new SoftReference&lt;TextToSpeech&gt;(new TextToSpeech(appContext,
                  new TextToSpeech.OnInitListener() {
                      @Override
                      public void onInit(int status) {
                          if (status == TextToSpeech.SUCCESS) {
                              speak(appContext, s);
                          } else {                                
                          }
                      }
                  }));
      } else {
          speak(appContext, s);
      }
  }
  
   private static void speak(Context context, String s) {
          if (sTts != null) {
              switch (sTts.get().setLanguage(Locale.getDefault())) {
              case TextToSpeech.LANG_COUNTRY_AVAILABLE:
              case TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE:
              case TextToSpeech.LANG_AVAILABLE: {
  
                  sTts.get().setPitch((float) 0.6);
                  sTts.get().setSpeechRate((float) 0.8);
  
                  final int currentRing=PublicParFun.GetCurrentVol(context, AudioManager.STREAM_RING);
                  final int currentPlay=PublicParFun.GetCurrentVol(context, AudioManager.STREAM_MUSIC);
  
                  PublicParFun.SetRingVol(context, 0);
                  PublicParFun.SetPlayVol(context,1000000);
  
                  final Context myContext=context;
  
                  HashMap&lt;String, String&gt; ttsParameters = new HashMap&lt;String, String&gt;();
                  ttsParameters.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"stringId");
  
                  if (android.os.Build.VERSION.SDK_INT &gt;=15){
                      sTts.get().setOnUtteranceProgressListener(new UtteranceProgressListener()
                      {
                          @Override
                          public void onDone(String utteranceId)
                          {
                              PublicParFun.SetRingVol(myContext, currentRing);
                               PublicParFun.SetPlayVol(myContext,currentPlay);
                          }
  
                          @Override
                          public void onError(String utteranceId)
                          {
                              //also, set the volume back
                          }
  
                          @Override
                          public void onStart(String utteranceId)
                          {
                             // set the volume to max
                          }
                      });
  
                  }else{                  
                    sTts.get().setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() {
                        @Override
                        public void onUtteranceCompleted(String utteranceId) {
                           PublicParFun.SetRingVol(myContext, currentRing);
                           PublicParFun.SetPlayVol(myContext,currentPlay);
                      }
                     });
                  }
                  sTts.get().speak(s, TextToSpeech.QUEUE_ADD, ttsParameters);
                  break;
              }
              case TextToSpeech.LANG_MISSING_DATA: {
                  break;
              }
              case TextToSpeech.LANG_NOT_SUPPORTED: // not much to do here
              }
          }
      }
  </code></pre>
  
  <p>}</p>
  
  <p><strong>Edit Again</strong></p>
  
  <p>I test many times, when sTts.get().speak(s, TextToSpeech.QUEUE_ADD, ttsParameters) speak a short string, the  sTts.get().setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() is invoked correctly.</p>
  
  <p>but if  sTts.get().speak(s, TextToSpeech.QUEUE_ADD, ttsParameters) speak a long string (about 15 seconds), it seems that  sTts.get().setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() is not be invoked. Why?</p>
  
  <pre><code>        sTts.get().setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() {
                @Override
                public void onUtteranceCompleted(String utteranceId) {
                   PublicParFun.SetRingVol(myContext, currentRing);
                   PublicParFun.SetPlayVol(myContext,currentPlay);
              }
             });
  </code></pre>