浏览代码

完善tts

yangchong 3 年之前
父节点
当前提交
5a7ddcf273

+ 36 - 10
AudioPlayer/src/main/java/com/yc/audioplayer/player/DefaultTtsPlayer.java

@@ -13,7 +13,15 @@ import com.yc.videotool.VideoLogUtils;
 import java.util.HashMap;
 import java.util.Locale;
 
-
+/**
+ * <pre>
+ *     @author yangchong
+ *     email  : yangchong211@163.com
+ *     time  : 2018/8/6
+ *     desc  : tts播放player
+ *     revise:
+ * </pre>
+ */
 public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpeech.OnInitListener {
 
     private TextToSpeech mTts;
@@ -24,6 +32,9 @@ public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpee
     private volatile boolean mReady = false;
     private final Context mContext;
     private InterPlayListener mPlayListener;
+    /**
+     * 创建tts监听
+     */
     private final OnCompleteListener mOnCompleteListener = new OnCompleteListener();
 
     public DefaultTtsPlayer(Context context) {
@@ -59,13 +70,17 @@ public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpee
         try {
             if (!mReady  && (TextToSpeech.SUCCESS == status) && this.mTts != null) {
                 VideoLogUtils.i("Initialize TTS success");
-                final Locale locale = mContext.getApplicationContext().getResources().getConfiguration().locale;
+                //获取locale
+                final Locale locale = mContext.getApplicationContext()
+                        .getResources().getConfiguration().locale;
                 if (locale != null) {
                     VideoLogUtils.i("tts isLanguageAvailable " + mTts.isLanguageAvailable(locale) +
-                        "; variant is " + locale.getVariant() + "; locale is " + locale + " ; country  is " + locale
-                        .getCountry());
+                        "; variant is " + locale.getVariant() +
+                            "; locale is " + locale + " ; country  is " + locale.getCountry());
                 }
-                switch (this.mTts.setLanguage(null != locale ? locale : Locale.getDefault())) {
+                //设置朗读语言
+                int setLanguage = this.mTts.setLanguage(null != locale ? locale : Locale.getDefault());
+                switch (setLanguage) {
                     case TextToSpeech.LANG_MISSING_DATA:
                         VideoLogUtils.i("TTS set language: Language missing data");
                         break;
@@ -85,6 +100,8 @@ public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpee
                         VideoLogUtils.i("TTS set language: Unknown error");
                         break;
                 }
+            } else if (TextToSpeech.ERROR == status) {
+                VideoLogUtils.i("Initialize TTS error");
             } else {
                 VideoLogUtils.i("Initialize TTS error");
             }
@@ -92,11 +109,11 @@ public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpee
             e.printStackTrace();
             VideoLogUtils.i(e.getMessage());
         }
-
     }
 
     @Override
     public void pause() {
+        //停止tts播放
         mTts.stop();
     }
 
@@ -108,15 +125,22 @@ public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpee
                 this.mTts.stop();
             }
 
+            String tts = data.getTts();
+            //添加tts监听
             this.mTts.setOnUtteranceProgressListener(mOnCompleteListener);
             HashMap<String, String> map = new HashMap<>();
-            map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, data.getTts());
-            this.mTts.speak(data.getTts(), TextToSpeech.QUEUE_FLUSH, map);
+            map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, tts);
+            //tts播报
+            //第一个参数播放的内容
+            //第二个参数表示
+            //第三个参数表示
+            this.mTts.speak(tts, TextToSpeech.QUEUE_FLUSH, map);
         }
     }
 
     @Override
     public void release() {
+        //关闭TTS
         this.mTts.shutdown();
         this.mReady = false;
     }
@@ -128,6 +152,7 @@ public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpee
 
     @Override
     public void stop() {
+        //停止播报
         mTts.stop();
     }
     
@@ -138,7 +163,7 @@ public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpee
         }
 
         /**
-         * 播放完成
+         * 播放完成。这个是播报完毕的时候 每一次播报完毕都会走
          * @param utteranceId                       话语id
          */
         @Override
@@ -160,7 +185,8 @@ public class DefaultTtsPlayer extends AbstractAudioWrapper implements TextToSpee
         }
 
         /**
-         * 播放开始
+         * 播放开始。这个是开始的时候。是先发声之后才会走这里
+         * 调用isSpeaking()方法在这为true
          * @param utteranceId                       话语id
          */
         @Override

+ 9 - 1
AudioPlayer/src/main/java/com/yc/audioplayer/player/MediaAudioPlayer.java

@@ -11,7 +11,15 @@ import com.yc.audioplayer.bean.AudioPlayData;
 import com.yc.audioplayer.inter.InterPlayListener;
 import com.yc.videotool.VideoLogUtils;
 
-
+/**
+ * <pre>
+ *     @author yangchong
+ *     email  : yangchong211@163.com
+ *     time  : 2018/8/6
+ *     desc  : 音频播放player
+ *     revise:
+ * </pre>
+ */
 public class MediaAudioPlayer extends AbstractAudioWrapper {
 
     private InterPlayListener mPlayListener;

+ 10 - 0
AudioPlayer/src/main/java/com/yc/audioplayer/wrapper/AbstractAudioWrapper.java

@@ -4,8 +4,18 @@ package com.yc.audioplayer.wrapper;
 import com.yc.audioplayer.inter.InterAudio;
 import com.yc.audioplayer.inter.InterPlayListener;
 
+/**
+ * <pre>
+ *     @author yangchong
+ *     email  : yangchong211@163.com
+ *     time  : 2018/8/6
+ *     desc  : tts抽象类,实现播放监听接口,和音频播放接口
+ *     revise:
+ * </pre>
+ */
 public abstract class AbstractAudioWrapper implements InterAudio, InterPlayListener {
 
     public final Object mMutex = new Object();
 
+
 }

+ 1 - 0
Demo/src/main/AndroidManifest.xml

@@ -128,6 +128,7 @@
         <activity android:name="com.yc.ycvideoplayer.music.MusicPlayerActivity"/>
         <activity android:name="com.yc.ycvideoplayer.m3u8.M3u8Activity"/>
         <activity android:name="com.yc.ycvideoplayer.audio.AudioActivity"/>
+        <activity android:name="com.yc.ycvideoplayer.audio.TTSAudioActivity"/>
     </application>
 
 </manifest>

+ 6 - 0
Demo/src/main/java/com/yc/ycvideoplayer/audio/AudioActivity.java

@@ -1,5 +1,6 @@
 package com.yc.ycvideoplayer.audio;
 
+import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.Button;
@@ -27,6 +28,7 @@ public class AudioActivity extends AppCompatActivity implements View.OnClickList
     private Button btnRelease;
     private Button btnBrazil;
     private Button btnTts;
+    private Button btnTtsDemo;
 
 
     @Override
@@ -45,6 +47,7 @@ public class AudioActivity extends AppCompatActivity implements View.OnClickList
         btnRelease = findViewById(R.id.btn_release);
         btnBrazil = findViewById(R.id.btn_brazil);
         btnTts = findViewById(R.id.btn_tts);
+        btnTtsDemo = findViewById(R.id.btn_tts_demo);
 
         btnInit.setOnClickListener(this);
         btnSpeakTts.setOnClickListener(this);
@@ -57,6 +60,7 @@ public class AudioActivity extends AppCompatActivity implements View.OnClickList
         btnRelease.setOnClickListener(this);
         btnBrazil.setOnClickListener(this);
         btnTts.setOnClickListener(this);
+        btnTtsDemo.setOnClickListener(this);
     }
 
 
@@ -111,6 +115,8 @@ public class AudioActivity extends AppCompatActivity implements View.OnClickList
             AudioService.getInstance().play(playData);
         } else if (v == btnTts){
             AudioService.getInstance().playTts("逗比,这个是tts");
+        } else if (v == btnTtsDemo){
+            startActivity(new Intent(this,TTSAudioActivity.class));
         }
     }
 }

+ 149 - 0
Demo/src/main/java/com/yc/ycvideoplayer/audio/TTSAudioActivity.java

@@ -0,0 +1,149 @@
+package com.yc.ycvideoplayer.audio;
+
+import android.os.Bundle;
+import android.speech.tts.TextToSpeech;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import com.yc.videotool.VideoLogUtils;
+
+import org.yc.ycvideoplayer.R;
+
+import java.util.Locale;
+
+public class TTSAudioActivity extends AppCompatActivity implements View.OnClickListener {
+
+    private Button btnInit;
+    private Button btnSpeakTts1;
+    private Button btnSpeakTts2;
+    private Button btnSpeakTts3;
+    private Button btnSpeakTts4;
+    private Button btnResume;
+    private Button btnStop;
+    private Button btnHighPriority;
+    private Button btnRelease;
+    private Button btnBrazil;
+    private Button btnTts;
+
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_audio_tts);
+
+        btnInit = findViewById(R.id.btn_init);
+        btnSpeakTts1 = findViewById(R.id.btn_speak_tts1);
+        btnSpeakTts2 = findViewById(R.id.btn_speak_tts2);
+        btnSpeakTts3 = findViewById(R.id.btn_speak_tts3);
+        btnSpeakTts4 = findViewById(R.id.btn_speak_tts4);
+        btnResume = findViewById(R.id.btn_resume);
+        btnStop = findViewById(R.id.btn_stop);
+        btnHighPriority = findViewById(R.id.btn_high_priority);
+        btnRelease = findViewById(R.id.btn_release);
+        btnBrazil = findViewById(R.id.btn_brazil);
+        btnTts = findViewById(R.id.btn_tts);
+
+        btnInit.setOnClickListener(this);
+        btnSpeakTts1.setOnClickListener(this);
+        btnSpeakTts2.setOnClickListener(this);
+        btnSpeakTts3.setOnClickListener(this);
+        btnSpeakTts4.setOnClickListener(this);
+        btnResume.setOnClickListener(this);
+        btnStop.setOnClickListener(this);
+        btnHighPriority.setOnClickListener(this);
+        btnRelease.setOnClickListener(this);
+        btnBrazil.setOnClickListener(this);
+        btnTts.setOnClickListener(this);
+    }
+
+
+    @Override
+    public void onClick(View v) {
+        if (v == btnInit){
+            init();
+        } else if (v == btnSpeakTts1){
+            if (textToSpeech!=null){
+                textToSpeech.speak("简单播放tts", TextToSpeech.QUEUE_FLUSH, null);
+            }
+        } else if (v == btnSpeakTts2){
+            if (textToSpeech!=null){
+                for (int i=0 ; i<5 ; i++){
+                    textToSpeech.speak("简单播放tts,"+i, TextToSpeech.QUEUE_FLUSH, null);
+                }
+            }
+        } else if (v == btnSpeakTts3){
+            if (textToSpeech!=null){
+                for (int i=0 ; i<5 ; i++){
+                    if (!textToSpeech.isSpeaking()){
+                        textToSpeech.speak("简单播放tts,"+i, TextToSpeech.QUEUE_FLUSH, null);
+                    }
+                }
+            }
+        } else if (v == btnSpeakTts4){
+            if (textToSpeech!=null){
+                for (int i=0 ; i<5 ; i++){
+                    textToSpeech.speak("简单播放,"+i, TextToSpeech.QUEUE_ADD, null);
+                }
+            }
+        } else if (v == btnResume){
+        } else if (v == btnStop){
+            if (textToSpeech!=null){
+                textToSpeech.stop();
+            }
+        } else if (v == btnHighPriority){
+
+        } else if (v == btnRelease){
+        } else if (v == btnBrazil){
+        } else if (v == btnTts){
+        }
+    }
+
+    private TextToSpeech textToSpeech;
+    private void init(){
+        textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
+            @Override
+            public void onInit(int status) {
+                if ((TextToSpeech.SUCCESS == status) && textToSpeech != null) {
+                    VideoLogUtils.i("Initialize TTS success");
+                    //获取locale
+                    final Locale locale = TTSAudioActivity.this.getApplicationContext()
+                            .getResources().getConfiguration().locale;
+                    if (locale != null) {
+                        VideoLogUtils.i("tts isLanguageAvailable " + textToSpeech.isLanguageAvailable(locale) +
+                                "; variant is " + locale.getVariant() +
+                                "; locale is " + locale + " ; country  is " + locale.getCountry());
+                    }
+                    //设置朗读语言
+                    int setLanguage = textToSpeech.setLanguage(null != locale ? locale : Locale.getDefault());
+                    switch (setLanguage) {
+                        case TextToSpeech.LANG_MISSING_DATA:
+                            VideoLogUtils.i("TTS set language: Language missing data");
+                            break;
+                        case TextToSpeech.LANG_NOT_SUPPORTED:
+                            VideoLogUtils.i("TTS set language: Language not supported");
+                            break;
+                        case TextToSpeech.LANG_AVAILABLE:
+                            VideoLogUtils.i("TTS set language: Language available");
+                            break;
+                        case TextToSpeech.LANG_COUNTRY_AVAILABLE:
+                            VideoLogUtils.i("TTS set language: Language country available");
+                            break;
+                        case TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE:
+                            VideoLogUtils.i("TTS set language: Language country var available");
+                            break;
+                        default:
+                            VideoLogUtils.i("TTS set language: Unknown error");
+                            break;
+                    }
+                } else if (TextToSpeech.ERROR == status) {
+                    VideoLogUtils.i("Initialize TTS error");
+                } else {
+                    VideoLogUtils.i("Initialize TTS error");
+                }
+            }
+        });
+    }
+
+}

+ 6 - 0
Demo/src/main/res/layout/activity_audio.xml

@@ -76,6 +76,12 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:text="play_tts"/>
+
+        <Button
+            android:id="@+id/btn_tts_demo"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="play_tts_demo"/>
     </LinearLayout>
 
 </RelativeLayout>

+ 81 - 0
Demo/src/main/res/layout/activity_audio_tts.xml

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:orientation="vertical">
+
+        <Button
+            android:id="@+id/btn_init"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="初始化tts" />
+
+        <Button
+            android:id="@+id/btn_speak_tts1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="简单播放tts" />
+
+        <Button
+            android:id="@+id/btn_speak_tts2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="循环简单播放tts,有问题的" />
+
+        <Button
+            android:id="@+id/btn_speak_tts3"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="循环简单播放tts,增加判断" />
+
+        <Button
+            android:id="@+id/btn_speak_tts4"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="正确循环播放tts" />
+
+        <Button
+            android:id="@+id/btn_speak_tts5"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="正确循环播放tts" />
+
+        <Button
+            android:id="@+id/btn_stop"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="stop" />
+
+        <Button
+            android:id="@+id/btn_high_priority"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="HIGH_PRIORITY" />
+
+        <Button
+            android:id="@+id/btn_release"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="release" />
+        <Button
+            android:id="@+id/btn_brazil"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="葡萄牙语言"/>
+        <Button
+            android:id="@+id/btn_tts"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="play_tts"/>
+    </LinearLayout>
+
+</RelativeLayout>

+ 1 - 1
VideoSqlLite/src/main/java/com/yc/videosqllite/disk/DiskLruCacheWrapper.java

@@ -6,7 +6,7 @@ import androidx.annotation.Nullable;
 import com.yc.videosqllite.manager.CacheConfig;
 import com.yc.videosqllite.manager.LocationManager;
 import com.yc.videosqllite.model.SafeKeyGenerator;
-import com.yc.videosqllite.utils.VideoLogUtils;
+import com.yc.videotool.VideoLogUtils;
 
 import java.io.File;
 import java.io.IOException;

+ 1 - 1
VideoSqlLite/src/main/java/com/yc/videosqllite/disk/SqlLiteCache.java

@@ -4,7 +4,7 @@ import com.yc.videosqllite.manager.CacheConfig;
 import com.yc.videosqllite.manager.LocationManager;
 import com.yc.videosqllite.model.SafeKeyGenerator;
 import com.yc.videosqllite.model.VideoLocation;
-import com.yc.videosqllite.utils.VideoLogUtils;
+import com.yc.videotool.VideoLogUtils;
 
 import java.io.File;
 

+ 1 - 1
VideoSqlLite/src/main/java/com/yc/videosqllite/manager/LocationManager.java

@@ -7,7 +7,7 @@ import com.yc.videosqllite.cache.VideoMapCache;
 import com.yc.videosqllite.disk.DiskFileUtils;
 import com.yc.videosqllite.disk.SqlLiteCache;
 import com.yc.videosqllite.model.VideoLocation;
-import com.yc.videosqllite.utils.VideoLogUtils;
+import com.yc.videotool.VideoLogUtils;
 
 import java.io.IOException;
 

+ 1 - 1
VideoSqlLite/src/main/java/com/yc/videosqllite/model/SafeKeyGenerator.java

@@ -3,7 +3,7 @@ package com.yc.videosqllite.model;
 import com.yc.videosqllite.cache.VideoLruCache;
 import com.yc.videosqllite.manager.CacheConfig;
 import com.yc.videosqllite.manager.LocationManager;
-import com.yc.videosqllite.utils.VideoLogUtils;
+import com.yc.videotool.VideoLogUtils;
 import com.yc.videotool.VideoMd5Utils;
 
 /**

+ 8 - 0
VideoTool/src/main/java/com/yc/videotool/VideoLogUtils.java

@@ -49,6 +49,14 @@ public final class VideoLogUtils {
         }
     }
 
+    public static void d(Object object){
+        if(isLog){
+            //这个方法 建议 Debug 进入不执行,因为 object 会进行字符串+拼接,产生大量内存对象。
+            //Log.d(TAG, object.toString());
+            Log.d(TAG, " log : " + object);
+        }
+    }
+
     public static void i(String message) {
         if(isLog){
             Log.i(TAG, message);

+ 155 - 0
read/54.TTS音频播放基础.md

@@ -0,0 +1,155 @@
+# TTS音频播放基础
+#### 目录介绍
+- 01.TTS简单的描述
+- 02.TTS简单的案例
+- 03.TTS播报监听处理
+- 04.TTS播报异常分析
+- 05.TTS播放音频案例
+- 06.TTS播放测试用例
+- 08.TTS接口设计架构
+
+
+
+
+
+### 01.TTS简单的描述
+- TTS全称Text  To Speech ,是文本转语音服务
+
+
+
+### 02.TTS简单的案例
+#### 2.1 初始化tts
+- 代码如下所示
+    ```
+    textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
+        @Override
+        public void onInit(int status) {
+            if (!mReady  && (TextToSpeech.SUCCESS == status) && textToSpeech != null) {
+                VideoLogUtils.i("Initialize TTS success");
+                //获取locale
+                final Locale locale = mContext.getApplicationContext()
+                        .getResources().getConfiguration().locale;
+                if (locale != null) {
+                    VideoLogUtils.i("tts isLanguageAvailable " + mTts.isLanguageAvailable(locale) +
+                            "; variant is " + locale.getVariant() +
+                            "; locale is " + locale + " ; country  is " + locale.getCountry());
+                }
+                //设置朗读语言
+                int setLanguage = this.textToSpeech.setLanguage(null != locale ? locale : Locale.getDefault());
+                switch (setLanguage) {
+                    case TextToSpeech.LANG_MISSING_DATA:
+                        VideoLogUtils.i("TTS set language: Language missing data");
+                        break;
+                    case TextToSpeech.LANG_NOT_SUPPORTED:
+                        VideoLogUtils.i("TTS set language: Language not supported");
+                        break;
+                    case TextToSpeech.LANG_AVAILABLE:
+                        VideoLogUtils.i("TTS set language: Language available");
+                        break;
+                    case TextToSpeech.LANG_COUNTRY_AVAILABLE:
+                        VideoLogUtils.i("TTS set language: Language country available");
+                        break;
+                    case TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE:
+                        VideoLogUtils.i("TTS set language: Language country var available");
+                        break;
+                    default:
+                        VideoLogUtils.i("TTS set language: Unknown error");
+                        break;
+                }
+            } else if (TextToSpeech.ERROR == status) {
+                VideoLogUtils.i("Initialize TTS error");
+            } else {
+                VideoLogUtils.i("Initialize TTS error");
+            }
+        }
+    });
+    ```
+
+
+#### 2.2 如何进行初始化
+- 如何进行播放?
+    ```
+    textToSpeech.speak(tts, TextToSpeech.QUEUE_FLUSH, null);
+    ```
+- 循环播放语音
+    - 想让他报个2-3遍或者循环播报的时候,我们来试一下
+    ```
+    for (int i=0 ; i<5 ; i++){
+        textToSpeech.speak("简单播放tts,"+i, TextToSpeech.QUEUE_FLUSH, null);
+    }
+    ```
+    - 简单的不行,但是问题来了,一段长的文字他只播报前面几个字,然后又重新开始播报。
+    - 这是因为textToSpeech.speak(tts, TextToSpeech.QUEUE_FLUSH, null);这个方法会自动关闭掉上面一个播报的内容,从而进行新一轮的播报。
+- 播放完成后再播放
+    - 要等上一条播报完整了再进行播报,该如何操作呢?那么可以TTS有 isSpeaking() 这个方法
+    ```
+    for (int i=0 ; i<5 ; i++){
+        if (!textToSpeech.isSpeaking()){
+            textToSpeech.speak("简单播放tts,"+i, TextToSpeech.QUEUE_FLUSH, null);
+        }
+    }
+    ```
+    - 这样就可以播全了嘛? 非也,for循环飞快的跑只要发现在speaking那么直接跳过开始走下一个i
+- 如何正确循环播放
+    ```
+    for (int i=0 ; i<5 ; i++){
+        textToSpeech.speak("简单播放,"+i, TextToSpeech.QUEUE_ADD, null);
+    }
+    ```
+    - 这样就相当于在一个消息队列然后进行循环的播报。
+
+
+### 03.TTS播报监听处理
+- 关于监听tts状态如下所示:
+    ```
+    private final class OnCompleteListener extends UtteranceProgressListener {
+    
+        OnCompleteListener() {
+    
+        }
+    
+        /**
+         * 播放完成。这个是播报完毕的时候 每一次播报完毕都会走
+         * @param utteranceId                       话语id
+         */
+        @Override
+        public void onDone(final String utteranceId) {
+            VideoLogUtils.i("TTSPlayer OnCompleteListener onDone");
+            onCompleted();
+        }
+    
+        /**
+         * 播放异常
+         * @param utteranceId                       话语id
+         */
+        @Override
+        public void onError(final String utteranceId) {
+            VideoLogUtils.i("TTSPlayer OnCompleteListener onError");
+            stop();
+            onError("TTSPlayer has play fail : " + utteranceId);
+            onCompleted();
+        }
+    
+        /**
+         * 播放开始。这个是开始的时候。是先发声之后才会走这里
+         * 调用isSpeaking()方法在这为true
+         * @param utteranceId                       话语id
+         */
+        @Override
+        public void onStart(final String utteranceId) {
+    
+        }
+    }
+    ```
+
+
+### 08.TTS接口设计架构
+
+
+### 参考
+- https://blog.csdn.net/qq_30359699/article/details/105388575
+- https://blog.csdn.net/awodefengduanwu/article/details/105683306
+
+
+
+

+ 39 - 0
read/62.视频内存优化治理.md

@@ -0,0 +1,39 @@
+# 视频内存优化治理
+#### 目录介绍
+
+
+
+
+
+
+
+
+
+
+
+### 关于log日志
+- log 方法内存开销过大。建议这个方法 建议 Debug 进入执行 ,但是正是包不执行,因为 object 会进行字符串+拼接,产生大量内存对象。
+```
+public static void d(Object object){
+    //这个方法 建议 Debug 进入执行 ,但是正是包不执行,因为 object 会进行字符串+拼接,产生大量内存对象。
+    //Log.d(TAG, object.toString());
+    Log.d(TAG, " log : " + object);
+}
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+