TextToSpeakAikit

package org.cocos2dx.javascript;

import static android.media.AudioAttributes.CONTENT_TYPE_SPEECH;
import static android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY;
import static android.media.AudioAttributes.USAGE_MEDIA;
import static android.media.AudioTrack.MODE_STREAM;

import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioTrack;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.speech.tts.UtteranceProgressListener;
import android.speech.tts.Voice;
import android.util.Log;
import android.widget.Toast;

import com.iflytek.aikit.core.AeeEvent;
import com.iflytek.aikit.core.AiHandle;
import com.iflytek.aikit.core.AiHelper;
import com.iflytek.aikit.core.AiInput;
import com.iflytek.aikit.core.AiRequest;
import com.iflytek.aikit.core.AiResponse;
import com.iflytek.aikit.core.AiResponseListener;
import com.iflytek.aikit.core.CoreListener;
import com.iflytek.aikit.core.ErrType;
import com.iflytek.aikit.core.JLibrary;

import org.cocos2dx.lib.BuildConfig;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Stack;

public class TextToSpeakAikit implements AiResponseListener, ITextToSpeak {

    private static final String TAG = "XzTextToSpeechAikit";

    private static final String UTTERANCE_ID_PREFIX = "talkback_";
    public static final String AiKit_Start = "aikit";
    /**
     * Denotes a successful operation.
     */
    public static final int SUCCESS = 0;
    /**
     * Denotes a generic operation failure.
     */
    public static final int ERROR = -1;

    /**
     * Denotes a stop requested by a client. It's used only on the service side of the API, client should never expect
     * to see this result code.
     */
    public static final int STOPPED = -2;

    /**
     * Denotes a failure of a TTS engine to synthesize the given input.
     */
    public static final int ERROR_SYNTHESIS = -3;

    /**
     * Denotes a failure of a TTS service.
     */
    public static final int ERROR_SERVICE = -4;

    /**
     * Denotes a failure related to the output (audio device or a file).
     */
    public static final int ERROR_OUTPUT = -5;

    /**
     * Denotes a failure caused by a network connectivity problems.
     */
    public static final int ERROR_NETWORK = -6;

    /**
     * Denotes a failure caused by network timeout.
     */
    public static final int ERROR_NETWORK_TIMEOUT = -7;

    /**
     * Denotes a failure caused by an invalid request.
     */
    public static final int ERROR_INVALID_REQUEST = -8;

    /**
     * Denotes a failure caused by an unfinished download of the voice data.
     *
     * @see Engine#KEY_FEATURE_NOT_INSTALLED
     */
    public static final int ERROR_NOT_INSTALLED_YET = -9;

    /**
     * Queue mode where all entries in the playback queue (media to be played and text to be synthesized) are dropped
     * and replaced by the new entry. Queues are flushed with respect to a given calling app. Entries in the queue from
     * other callees are not discarded.
     */
    public static final int QUEUE_FLUSH = 0;
    /**
     * Queue mode where the new entry is added at the end of the playback queue.
     */
    public static final int QUEUE_ADD = 1;
    /**
     * Queue mode where the entire playback queue is purged. This is different from {@link #QUEUE_FLUSH} in that all
     * entries are purged, not just entries from a given caller.
     *
     * @hide
     */
    static final int QUEUE_DESTROY = 2;
    public static final int SPEECH_FLUSH_ALL = 3;

    /**
     * Denotes the language is available exactly as specified by the locale.
     */
    public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;

    /**
     * Denotes the language is available for the language and country specified by the locale, but not the variant.
     */
    public static final int LANG_COUNTRY_AVAILABLE = 1;

    /**
     * Denotes the language is available for the language by the locale, but not the country and variant.
     */
    public static final int LANG_AVAILABLE = 0;

    /**
     * Denotes the language data is missing.
     */
    public static final int LANG_MISSING_DATA = -1;

    /**
     * Denotes the language is not supported.
     */
    public static final int LANG_NOT_SUPPORTED = -2;


    private final Context mContext;
    private OnInitListener mInitListener;
    // Written from an unspecified application thread, read from
    // a binder thread.
    private final Object mStartLock = new Object();

    // Whether to initialize this TTS object with the default engine,
    // if the requested engine is not available. Valid only if mRequestedEngine
    // is not null. Used only for testing, though potentially useful API wise
    // too.
    public final boolean mUseFallback;
    private final Bundle mParams = new Bundle();
    //
    private String uriPath = "";
    public Toast mToast;
    // // 默认发音人
    private String voicer = "";
    // private int mSpeed = 0;
    // private int mRate = 0;
    // 缓冲进度
    private int mPercentForBuffering = 0;
    // 播放进度
    private int mPercentForPlaying = 0;

    private String mUId = "";
    //    private boolean mIsUseAccessibility=true;
    private boolean mIsUseA11yThis = false;
    private boolean mIsBufferComplete = false;
    private int mBufferSize;
    private AudioThread mAudioRunnable;
    private String vcn = "xiaoyan";
    private int lan = 2;
    private int mId;
    private final static String lans = "01xiaoyan01xiaofeng01chongchong01xiaofang01xiaoyuan02catherine02john03mariane05xiaolin05zhongcun06keshu08abha09christiance12xiaomei15anna16kim23felisa48rania48mohamed";
    private LinkedList<String> mSpeakBuf = new LinkedList<>();
    private boolean mSpeaking;

    public interface OnInitListener {
        void onInit(int status);
    }

    private static String aikitPathReal = "/xzhd/aikit/";
    private static String aikitPathInData = "";

    public TextToSpeakAikit(Context context, String voicer) {
        mContext = context;
        mInitListener = null;
        mUseFallback = true;
        vcn = voicer.replaceAll("aikit", "");
        int index = lans.indexOf(vcn);
        if (index > 0) {
            lan = Integer.parseInt(lans.substring(index - 2, index));
        } else {
            lan = 1;
        }
        lan = 6;
        mIsBufferComplete = false;
        initSuccess = false;


        copyXttsResToAikit();
        String workDir = aikitPathInData;

        initSdk("5ad41b5a", APIKey, APISecret, workDir);

        int sampleRateInHz = 16000;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int channelCount = AudioFormat.CHANNEL_OUT_MONO;
        min_buffer_size = AudioTrack.getMinBufferSize(sampleRateInHz, channelCount, audioFormat);
        initAudioA11y();
        initAudioMedia();
        startAudioThread();
    }

    void copyXttsResToAikit() {    ///data/user_de/0/org.cocos2d.demo/files/xzhd/aikit/
        File sdDir = new File(mContext.getFilesDir(), aikitPathReal);///data/user_de/0/org.cocos2d.demo/files/xzhd/aikit/
        aikitPathInData = sdDir.getAbsolutePath() + "/";
        FileUtils.createDirectory(aikitPathInData);
        try {
            FileUtils.copyFiles(mContext, "xtts", aikitPathInData);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private AiHandle aiHandle;
    private AiInput.Builder paramBuilder = AiInput.builder();
    private AiInput.Builder dataBuilder = AiInput.builder();

    private volatile UtteranceProgressListener mUtteranceProgressListener;

    public void setOnUtteranceProgressListener(UtteranceProgressListener listener) {
        mUtteranceProgressListener = listener;
    }

    public Set<Voice> getVoices() {

        return null;
    }

    private final static String APIKey = "763f5e91d4bf53c1bb61e37d54b57407";
    private final static String APISecret = "cc07aae65ad3b1372f09e0695b6af57f";


    void initSdk(String appid, String apiKey, String apiSecret, String workDir) {
        //设定初始化参数
        int interval = 555;


        final JLibrary.Params params = JLibrary.Params.builder()
                .appId(appid)
                .apiKey(apiKey)
                .apiSecret(apiSecret)
                .workDir(workDir)
                .authInterval(interval)
                .build();
        if (BuildConfig.DEBUG)
            Log.w(TAG, "initSdk: " + Arrays.toString(new File(workDir).listFiles()));
        //注册鉴权监听
//        appId=appid;
        JLibrary.getInst().registerListener(coreListener);
        //注册能力回调监听
        JLibrary.getInst().registerListener(this);
        JLibrary.getInst().registerListener(this);
        JLibrary.getInst().initEntry(mContext.getApplicationContext(), params);
    }

    private String abilityId = "e2e44feff";

    private void engineInit(String abilityId) {

        //引擎初始化
        int ret = AiHelper.getInst().engineInitNoParams(abilityId);
        if (ret == 0) {
            showInfo("引擎初始化成功: " + ret);
            initSuccess = true;
        } else {
            showInfo("引擎初始化失败: " + ret);
        }
    }

    //授权结果回调
    private CoreListener coreListener = new CoreListener() {
        @Override
        public void onAuthStateChange(final ErrType type, final int code) {

            switch (type) {
                case AUTH:
                    showInfo("授权状态:授权结果码" + code);
                    if (code == 0) {
                        engineInit(abilityId);
                    }
                    break;
                case HTTP:
                    showInfo("授权状态:HTTP认证结果" + code);
                    break;
                default:
                    showInfo("授权状态:其他错误");
            }
        }
    };

    //能力执行结果返回
    @Override
    public void onResult(String ability, int handleID, List<AiResponse> outputData, Object usrContext) {

      //  System.out.println("---------onResult-----------ability:" + ability + ",handleID:" + handleID);

        if (null != outputData && outputData.size() > 0) {
            for (int i = 0; i < outputData.size(); i++) {
                byte[] bytes = outputData.get(i).getValue();
                if (bytes == null) {
                    continue;
                }
                if (!isAudioPlayStart) {
                    // Log.i(TAG, "onEvent: start");
                    isAudioPlayStart = true;
                    showToast("开始播放");
                    if (mIsUseA11yThis) {
                        if (mAudio_a11y != null) {
                            mAudio_a11y.play();
                        }
                    } else {
                        if (mAudio_media != null) {
                            mAudio_media.play();
                        }
                    }
                    mBufferSize = 0;
                    mBufferTime = System.currentTimeMillis();
//                            mUtteranceProgressListener.onStart(mUId);

                } else {
//
                }


                addBufferToList(bytes);
            }
        }
    }

    //事件回调
    @Override
    public void onEvent(String ability, int handleID, int event, List<AiResponse> eventData, Object usrContext) {
      //  System.out.println("---------onEvent-----------ability:" + ability + ",handleID:" + handleID + ",event:" + event);
        if (event == AeeEvent.AEE_EVENT_END.getValue()) {  // 引擎计算结束事件
            if (aiHandle != null) {
                int ret = AiHelper.getInst().end(aiHandle);
//                        ttsFinished.set(true);

                if (ret == 0) {
                    aiHandle = null;
//                            if (ttsModel == 1) {
//                                showInfo("开始将文件写入本地");
//                                writeFile(getCacheArray());
//                            }
                }
            }
            mIsBufferComplete = true;
          //  System.out.println("---------onEvent-----AEE_EVENT_END------ability:" + ability + ",handleID:" + handleID + ",event:" + event);
            synchronized (mAudioRunnable.lock) {
                mAudioRunnable.lock.notify();
            }
            if (!isAudioPlayStart) {
                if (mUtteranceProgressListener != null)
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        mUtteranceProgressListener.onError(mUId, Engine.Speak_Error_onDone_Unkown);
                    }
                mSpeaking = false;
            }
//                    if (isChangePeople.get()) {
//                        ttsFinished.set(true);
//                        showInfo("合成结束···");
//                        if (playerFragment != null) {
//                            //可以开始播放
//                            playerFragment.setPlayStatus(1);
//                            playerFragment.setTTSStatus(2);
//                        }
//                        Message dataMsg = Message.obtain();
//                        dataMsg.what = MSG_END_HANDLE;
//                        eventHandle.sendMessage(dataMsg);
//                    } else {
//                        if (playerFragment != null) {
//                            //可以开始播放
//                            playerFragment.setPlayStatus(1);
//                            playerFragment.setTTSStatus(2);
//                        }
//                        Message dataMsg = Message.obtain();
//                        dataMsg.what = MSG_END_HANDLE;
//                        eventHandle.sendMessage(dataMsg);
//                    }
//                    if (saveLocalFragment != null && !isPress.get()) {
//                        saveLocalFragment.setTvStartIsSelect(true);
//                    }
//                    ttsFinished.set(true);
//                    showInfo("合成结束···");
        } else if (event == AeeEvent.AEE_EVENT_START.getValue()) {  // 引擎计算开始事件
            if (mUtteranceProgressListener != null)
                mUtteranceProgressListener.onStart(mUId);
            mSpeaking = true;
        } else if (event == AeeEvent.AEE_EVENT_PROGRESS.getValue()) {  // 引擎计算进度事件
            int pos = -1;
            int len = -1;
            for (int i = 0; i < eventData.size(); i++) {
                AiResponse aiOutput = eventData.get(i);
                if (aiOutput.getKey().equals("progress_pos")) {
                    pos = bytes2int(aiOutput.getValue());
                } else if (aiOutput.getKey().equals("progress_len")) {
                    len = bytes2int(aiOutput.getValue());
                }
            }

        }
    }

    private int bytes2int(byte[] bytes) {
        //如果不与0xff进行按位与操作,转换结果将出错。
        int int1 = bytes[0] & 0xff;
        int int2 = (bytes[1] & 0xff) << 8;
        int int3 = (bytes[2] & 0xff) << 16;
        int int4 = (bytes[3] & 0xff) << 24;
        return int1 | int2 | int3 | int4;
    }

    //错误通知,能力执行终止
    @Override
    public void onError(String ability, int handleID, int err, String msg, Object usrContext) {
//        System.out.println("---------onError-----------ability:" + ability + ",handleID:" + handleID + ",err:" + err + ",msg:" + msg);
//                ttsFinished.set(true);
//                if (playerFragment != null) {
//                    playerFragment.setTTSStatus(0);
//                    playerFragment.setPlayStatus(0);
//                }
//
//                if (saveLocalFragment != null && !isPress.get()) {
//                    saveLocalFragment.setTvStartIsSelect(true);
//                }
    }

    private void showInfo(final String info) {

    }

    private void initAudioA11y() {
        try {
            if (mAudio_a11y == null) {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    mAudio_a11y = new AudioTrack.Builder().setAudioAttributes(new AudioAttributes.Builder()
                                    .setUsage(USAGE_ASSISTANCE_ACCESSIBILITY)
                                    .setContentType(CONTENT_TYPE_SPEECH)
                                    .build())
                            .setBufferSizeInBytes(256)
                            //.setSessionId(AUDIO_SESSION_ID_GENERATE)
                            .setTransferMode(MODE_STREAM)
                            .setAudioFormat((new AudioFormat.Builder())
                                    .setChannelMask(channelCount)
                                    .setEncoding(audioFormat)
                                    .setSampleRate(sampleRateInHz)
                                    .build()).build();
                }

            }

            mAudio_a11y.play();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initAudioMedia() {
        try {
            if (mAudio_media == null) {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    mAudio_media = new AudioTrack.Builder().setAudioAttributes(new AudioAttributes.Builder()
                                    .setUsage(USAGE_MEDIA)
                                    .setContentType(CONTENT_TYPE_SPEECH)
                                    .build())
                            .setBufferSizeInBytes(256)
                            //.setSessionId(AUDIO_SESSION_ID_GENERATE)
                            .setTransferMode(MODE_STREAM)
                            .setAudioFormat((new AudioFormat.Builder())
                                    .setChannelMask(channelCount)
                                    .setEncoding(audioFormat)
                                    .setSampleRate(sampleRateInHz)
                                    .build()).build();
                }

            }

            mAudio_media.play();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private boolean initSuccess = false;

    public boolean isInitSuccess() {
//        return mTts != null;
        return initSuccess;
    }

//    public void showParam() {
//        if (mTts == null) {
//
//            return;
//        }
//        //SpeechConstant.VOICE_NAME: 发音人
//
//        //SpeechConstant.SPEED: 合成语速
//
//        //SpeechConstant.VOLUME: 合成音量
//
//        //SpeechConstant.PITCH: 合成语调
//
//        //SpeechConstant.BACKGROUND_SOUND: 背景音乐
//
//        //SpeechConstant.TTS_BUFFER_TIME: 合成音频缓冲时间
//
//        //SpeechConstant.STREAM_TYPE: 播放类型
//
//        //SpeechConstant.SAMPLE_RATE: 采样率
//
//        //SpeechConstant.TTS_AUDIO_PATH: 合成录音保存路径
//
//        //SpeechConstant.ENGINE_TYPE:引擎类型;
//
//
//        //ResourceUtil.TTS_RES_PATH:离线资源路径;
//
//        //ResourceUtil.ENGINE_START:启动离线引擎;
//
//        //SpeechConstant.TTS_FADING : 合成淡入淡出;
//
//        //SpeechConstant.AUDIO_FORMAT_AUE:音频流编解码格式;
//
//
//
//    }

//    public void showParamError() {
//        if (mTts == null) {
//
//            return;
//        }
//        //SpeechConstant.TTS_BUFFER_TIME: 合成音频缓冲时间
//
//        //SpeechConstant.STREAM_TYPE: 播放类型
//
//        //SpeechConstant.SAMPLE_RATE: 采样率
//
//        //SpeechConstant.TTS_AUDIO_PATH: 合成录音保存路径
//
//        //SpeechConstant.ENGINE_TYPE:引擎类型;
//
//
//        //ResourceUtil.TTS_RES_PATH:离线资源路径;
//
//        //ResourceUtil.ENGINE_START:启动离线引擎;
//
//        //SpeechConstant.TTS_FADING : 合成淡入淡出;
//
//        //SpeechConstant.AUDIO_FORMAT_AUE:音频流编解码格式;
//
//    }

    //获取发音人资源路径
//    private String getResourcePath(String voicerLocal) {
//        StringBuffer tempBuffer = new StringBuffer();
//        //合成通用资源
//        tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "tts/common.jet"));
//        tempBuffer.append(";");
//        //发音人资源
//        tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "tts/" + voicerLocal + ".jet"));
//
//        return tempBuffer.toString();
//    }

//    private String getResourcePathXtts(String voicerLocal) {
//        StringBuffer tempBuffer = new StringBuffer();
//        //合成通用资源
//        tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "xtts/common.jet"));
//        tempBuffer.append(";");
//        //发音人资源
//        tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "xtts/" + voicerLocal + ".jet"));
//
//        return tempBuffer.toString();
//    }

    //获取发音人资源路径
//    private String getResourcePathXtts(String voicerLocal, String jetPath) {
//
//        StringBuffer tempBuffer = new StringBuffer();
//        //合成通用资源
//        tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "xtts/common.jet"));
//        tempBuffer.append(";");
//        //发音人资源
//        tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.path, jetPath + "/" + voicerLocal + ".jet"));
//
//        return tempBuffer.toString();
//    }

//    //获取发音人资源路径
//    private String getResourcePath(String voicerLocal, String jetPath) {
//
//        StringBuffer tempBuffer = new StringBuffer();
//        //合成通用资源
//        tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "tts/common.jet"));
//        tempBuffer.append(";");
//        //发音人资源
//        tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.path, jetPath + "/" + voicerLocal + ".jet"));
//
//        return tempBuffer.toString();
//    }

//    /**
//     * 初始化监听。
//     */
//    private InitListener mTtsInitListener = new InitListener() {
//        @Override
//        public void onInit(int code) {
//
//            if (code != ErrorCode.SUCCESS) {
//                showToast("初始化失败,错误码:" + code);
//            } else {
//                //mTts.startSpeaking("欢迎使用心智助手", mTtsListener);
//
//                //            mTts.startSpeaking("初始化成功", mTtsListener);
//                // 初始化成功,之后可以调用startSpeaking方法
//                // 注:有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成,
//                // 正确的做法是将onCreate中的startSpeaking调用移至这里
//            }
//        }
//    };

    private void showToast(final String str) {
        if (BuildConfig.DEBUG) Log.w(TAG, "showToast: " + str);
        //    mToast.setText(str);
        //    mToast.show();
        //    LogTool.log(TAG, "showToast str: " + str);
    }

    private String mLastSpeak = "";

    public void stopSpeaking() {

//        mTts.stopSpeaking();
    }

    public List<String> spiltString(String text, int sumInLine) {
        List<String> strs = new ArrayList<String>();
        int startIndex = 0;
        int endIndex = 0;
        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);
            endIndex = i + 1;
            if (endIndex == text.length()) {
                if (ch == 10) {
                    endIndex = i;
                }
                strs.add(text.substring(startIndex, endIndex));
                break;
            }
            if (endIndex - startIndex == sumInLine) {
                if (ch == 10) {
                    endIndex = i;
                }
                strs.add(text.substring(startIndex, endIndex));
                startIndex = i + 1;
            } else {
                if (ch == 10) {
                    strs.add(text.substring(startIndex, endIndex - 1));
                    startIndex = i + 1;
                }
            }
        }
        return strs;
    }

    /**
     * Checks whether the TTS engine is busy speaking. Note that a speech item is considered complete once it's audio
     * data has been sent to the audio mixer, or written to a file. There might be a finite lag between this point, and
     * when the audio hardware completes playback.
     *
     * @return {@code true} if the TTS engine is speaking.
     */
    public boolean isSpeaking() {
//        if (null == mTts) {
        return mSpeaking;
//        }
//        return mTts.isSpeaking();
    }

    @Override
    public void destroy() {
        shutdown();
    }

    public boolean isNeedClearBuffers = false;

    public synchronized void setNeedClearBuffers(boolean needClearBuffers) {
        // Log.i(TAG, "setNeedClearBuffers: " + needClearBuffers);
        isNeedClearBuffers = needClearBuffers;
    }

    @Override
    public boolean speak(String text, int speed, int pitch, int volume, int scale) {
        buffers.clear();
//        AppTool.printCallStatck(TAG);
        int code = 0;
        mBufferTime = -1;
        mLastSpeak = text;
        mIsBufferComplete = false;
        isAudioPlayStart = false;
        showToast("speak " + text);
        if (aiHandle != null) {
            int ret = AiHelper.getInst().end(aiHandle);
            if (ret == 0) {
                aiHandle = null;
            }
        }
        setSpeedUp(scale);
        paramBuilder.clear();


        System.out.println("---------speak  text=" + text+",speed="+speed+",pitch="+pitch+",volume="+volume+",scale="+scale);
        System.out.println("---------speak  vcn=" + vcn+",lan="+lan+",speed="+speed+",pitch="+pitch+",volume="+volume);


        paramBuilder.param("vcn", vcn).   //必选参数,60020
                // :xiaoyan发音人60030:xiaofeng发音人69010:john英文发音人69020:catherine英文发音人,chongchong :65620
                  param("vcnModel", vcn).
                //1:中文, 2:英文, 3:法语, 5:日语, 6:俄语, 9:德语, 15:意大利语, 16:韩语, 23:西班牙语, 48:阿拉伯语, 50:阿拉伯语(Eg), 12:粤语, 8:印地语
                        param("language", lan).
                //reg  英文发音方式     int    0:引擎自动判断, 1:按字母发音, 2:按单词发音     否  0
                        param("reg", 2).
                //rdn  数字发音方式     int    0:引擎自动判断, 1:按数字发音, 2:按字符串发音    否  0
                        param("rdn", 0).
                param("speed", speed).    //可选参数,默认为0
                param("pitch", pitch).    //可选参数,默认为0
                param("volume", volume).   //可选参数,默认为0
                param("textEncoding", "UTF-8");   //可选参数,文本编码格式,默认为65001,UTF8格式
//        ttsFinished.set(false);
//        if(eventHandle != null){
//            eventHandle.removeCallbacksAndMessages(null);
//        }
        aiHandle = AiHelper.getInst().start(abilityId, paramBuilder.build(), null);
        if (aiHandle.getCode() != 0) {
            showInfo("start失败:" + aiHandle.getCode());
//            ttsFinished.set(true);
//            playerFragment.setTTSStatus(0);
//            playerFragment.setPlayStatus(0);
//            saveLocalFragment.setTvStartIsSelect(true);
            return false;
        }


        dataBuilder.clear();
        dataBuilder.text("text", mLastSpeak);
//        2.3 能力输出数据 数据段名称:audio 数据类型:音频
//        字段   含义     数据类型   取值范围   默认值    说明     必填
//        encoding     音频编码   string     lame, speex, opus, speex-wb    speex-wb   取值范围可枚举    否
        dataBuilder.audio("encoding", "raw");
//        sample_rate  采样率    int    16000, 8000    16000  音频采样率,可枚举  否
        dataBuilder.audio("sample_rate", sampleRateInHz + "");
//        channels     声道数    int    1, 2   1  声道数,可枚举    否
        dataBuilder.audio("channels", numChannels + "");
//        bit_depth    位深     int    16, 8  16     单位bit,可枚举  否
        dataBuilder.audio("bit_depth", "16");
//        data     音频数据   string           音频大小:0-10M     否
//        frame_size   帧大小    int    最小值:0, 最大值:1024    0  帧大小,默认0    否
//        totalLen = text.length();
//        IFlyPlayerManager.getInst().reSetPercent(totalLen);
        int ret = AiHelper.getInst().write(dataBuilder.build(), aiHandle);
        if (ret != 0) {
            showInfo(" write失败:" + ret);
//            ttsFinished.set(true);
//            playerFragment.setTTSStatus(0);
//            playerFragment.setPlayStatus(0);
//            saveLocalFragment.setTvStartIsSelect(true);
            return false;
        }
        //
        mIsUseA11yThis = false;
        mUId = getId();
        System.out.println("--------------------mUId=" + mUId);
        return true;
    }

    private String getId() {
        return String.valueOf(mId++);
    }

    @Override
    public boolean appendSpeak(String text, int speed, int pitch, int volume, int scale) {
        if (!isSpeaking())
            return speak(text, speed, pitch, volume, scale);
        mSpeakBuf.addLast(text);
        return true;
    }

    /**
     * Interrupts the current utterance (whether played or rendered to file) and discards other utterances in the queue.
     */
    public void stop() {
        // Log.i(TAG, "stop: ");
        mBufferTime = -1;

        /*if (null != mTts) {
            mTts.stopSpeaking();
        }*/
        buffers.clear();
        //setNeedClearBuffers(true);
        // Log.i(TAG, "stop:2 ");
        if (mIsUseA11yThis) {
            if (null != mAudio_a11y) {
                mAudio_a11y.stop();
            }
        } else {
            if (null != mAudio_media) {
                mAudio_media.stop();
            }
        }
        // Log.i(TAG, "stop:3 ");

    }

    public void shutdown() {

//        if (null != mTts) {
         mTts.destroy();
//        }
        if (null != mAudio_a11y) {
            mAudio_a11y.stop();
        }
        if (null != mAudio_media) {
            mAudio_media.stop();
        }
        stopAudioThread();
    }

    public void stopAll() {

//        if (null == mTts) {
//            return;
//        }
        buffers.clear();
        //setNeedClearBuffers(true);
        if (null != mAudio_a11y) {
            mAudio_a11y.stop();
        }
        if (null != mAudio_media) {
            mAudio_media.stop();
        }
//        if (mTts.isSpeaking()) {
//            stopSpeaking();
//        }
    }

    /**
     * Sets the speech rate.
     * <p>
     * This has no effect on any pre-recorded speech.
     *
     * @param speechRate Speech rate. {@code 1.0} is the normal speech rate, lower values slow down the speech ({@code 0.5} is
     *                   half the normal speech rate), greater values accelerate it ({@code 2.0} is twice the normal speech
     *                   rate).
     * @return {@link #ERROR} or {@link #SUCCESS}.
     */
    public int setSpeechRate(float speechRate) {
        if (speechRate > 0.0f) {
            int intRate = (int) (speechRate * 100);
            if (intRate > 0) {
                synchronized (mStartLock) {
                }
                return SUCCESS;
            }
        }
        return ERROR;
    }

    /**
     * @hide
     */
    public String getCurrentEngine() {
        return "";
    }

    @Deprecated
    public int setEngineByPackageName(String enginePackageName) {
        return SUCCESS;
    }

    /**
     * Gets the package name of the default speech synthesis engine.
     *
     * @return Package name of the TTS engine that the user has chosen as their default.
     */
    public String getDefaultEngine() {
        return "";
    }

    /**
     * Limit of length of input string passed to speak and synthesizeToFile.
     */
    public static int getMaxSpeechInputLength() {
        return 4000;
    }

    private boolean isAudioPlayStart = false;
    private static AudioTrack mAudio_a11y;
    private static AudioTrack mAudio_media;
    private static final int MIN_AUDIO_BUFFER_SIZE = 8192;

    private long mBufferTime;

    private boolean isAudioThreadStop = false;
    private LinkedList<byte[]> buffers = new LinkedList<>();

    private void startAudioThread() {
        isAudioThreadStop = false;
        mAudioRunnable = new AudioThread();
        new Thread(mAudioRunnable).start();
    }

    private void stopAudioThread() {
        isAudioThreadStop = true;
    }

    public void setSpeedUp(int speedUp) {

        if (sonic == null) {
            initSonic();
        }
        sonic.setSpeed(speedUp);
    }

    private void addBufferToList(byte[] buffer) {
        //
        if (isAudioThreadStop) {
            startAudioThread();
        }
        if (sonic == null) {
            initSonic();
        }
        buffers.addLast(buffer);
      //  System.out.println("---------addBufferToList-----------isAudioThreadStop:" + isAudioThreadStop + ",sonic:" + sonic + ",buffers.size():" + buffers.size());
        synchronized (mAudioRunnable.lock) {
            mAudioRunnable.lock.notify();
        }
    }


    Sonic sonic = null;
    int sampleRateInHz = 16000;
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    int channelCount = AudioFormat.CHANNEL_OUT_MONO;
    int numChannels = 1;
    int min_buffer_size = 0;

    private void initSonic() {
        sonic = new Sonic(sampleRateInHz, numChannels);
        int numRead, numWritten;
        boolean emulateChordPitch = false;
        int quality = 0;
        min_buffer_size = AudioTrack.getMinBufferSize(sampleRateInHz, channelCount, audioFormat);

        sonic.setSpeed(1.0f);
        //sonic.setPitch(0.5f);
        //sonic.setRate(1.0f);
        sonic.setVolume(1f);
        //sonic.setChordPitch(emulateChordPitch);
        //sonic.setQuality(quality);
    }

    private Handler myHandle = new Handler();

    private class AudioThread implements Runnable {
        private final Object lock = new Object();

        @Override
        public void run() {
            while (!isAudioThreadStop) {
//
//
//
                try {
                    byte[] buffer = buffers.pollFirst();
                    if (buffer != null) {
                        try {
//                            saveBufferToFile(buffer,mUId);
                            if (sonic.getSpeed() > .0f) {
//
                                int len = buffer.length;
                                sonic.writeBytesToStream(buffer, buffer.length);
                                int numWritten = 0;
                                byte[] outBuffer = new byte[len * 2];
                                numWritten = sonic.readBytesFromStream(outBuffer, len * 2);
                                mBufferSize += numWritten;
//
                                if (mIsUseA11yThis) {
                                    mAudio_a11y.write(outBuffer, 0, numWritten);
                                } else {
                                    mAudio_media.write(outBuffer, 0, numWritten);
                                }
//
                            } else {
                                mBufferSize += buffer.length;
                                if (mIsUseA11yThis) {
                                    mAudio_a11y.write(buffer, 0, buffer.length);
                                } else {
                                    mAudio_media.write(buffer, 0, buffer.length);
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else {
                        if (mIsBufferComplete) {
                            // Log.i(TAG, "mIsBufferComplete: ");
                            mIsBufferComplete = false;
                            int time = mBufferSize / (16000 * 2 / 1000);
                            long utime = System.currentTimeMillis() - mBufferTime;
                            // Log.i("fly", "run: " + time + ";" + utime);
                            mBufferTime = 0;
                            //if (utime < time) {
                            myHandle.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    if (mBufferTime == 0) {
                                        if (mIsUseA11yThis) {
                                            if (null != mAudio_a11y) {
                                                mAudio_a11y.stop();
                                            }
                                        } else {
                                            if (null != mAudio_media) {
                                                mAudio_media.stop();
                                            }
                                        }
                                        if (mUtteranceProgressListener != null)
                                            mUtteranceProgressListener.onDone(mUId);
                                        mSpeaking = false;
                                    }
                                }
                            }, Math.max(time - utime, 60));
                        }
                        try {
                            synchronized (lock) {
                                lock.wait();
                                //Log.i(TAG, "addBufferToList: wait");
                            }
                            //Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if (isNeedClearBuffers) {
                        setNeedClearBuffers(false);
                        if (buffers.size() > 0) {
                            //buffers.clear();
                            continue;
                        }
                        if (mIsUseA11yThis) {
                            if (null != mAudio_a11y) {
                                mAudio_a11y.stop();
                                mAudio_a11y.play();
                            }
                        } else {
                            if (null != mAudio_media) {
                                mAudio_media.stop();
                                mAudio_a11y.play();
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public class Engine {
        public static final int DEFAULT_RATE = 100;
        public static final int DEFAULT_PITCH = 100;
        public static final float DEFAULT_VOLUME = 1.0f;
        public static final float DEFAULT_PAN = 0.0f;

        public static final int USE_DEFAULTS = 0; // false
        //    public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
        public static final int CHECK_VOICE_DATA_PASS = 1;
        public static final int CHECK_VOICE_DATA_FAIL = 0;
        public static final int Speak_Error_onEvent_21002 = 10;
        public static final int Speak_Error_onDone_Unkown = 11;
        public static final int Speak_Error_onError_20999 = 12;

        public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
        public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
        public static final String KEY_PARAM_RATE = "rate";
        public static final String KEY_PARAM_VOICE_NAME = "voiceName";
        public static final String KEY_PARAM_LANGUAGE = "language";
        public static final String KEY_PARAM_COUNTRY = "country";
        public static final String KEY_PARAM_VARIANT = "variant";
        public static final String KEY_PARAM_ENGINE = "engine";
        public static final String KEY_PARAM_PITCH = "pitch";
        public static final String KEY_PARAM_STREAM = "streamType";
        public static final String KEY_PARAM_AUDIO_ATTRIBUTES = "audioAttributes";
        public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
        public static final String KEY_PARAM_VOLUME = "volume";
        public static final String KEY_PARAM_PAN = "pan";
        public static final String KEY_PARAM_SESSION_ID = "sessionId";
        public static final String KEY_FEATURE_NOT_INSTALLED = "notInstalled";
        public static final String KEY_FEATURE_NETWORK_TIMEOUT_MS = "networkTimeoutMs";
        public static final String KEY_FEATURE_NETWORK_RETRIES_COUNT = "networkRetriesCount";
    }

    public String getVoicer() {
        return voicer;
    }

    public void setVoicer(String voicer) {
        this.voicer = voicer;
    }

    public int getPercentForBuffering() {
        return mPercentForBuffering;
    }

    public void setPercentForBuffering(int mPercentForBuffering) {
        this.mPercentForBuffering = mPercentForBuffering;
    }

    public int getPercentForPlaying() {
        return mPercentForPlaying;
    }

    public void setPercentForPlaying(int mPercentForPlaying) {
        this.mPercentForPlaying = mPercentForPlaying;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值