diff --git a/common/build.gradle b/common/build.gradle index 2cd214fe1..c08a2d5dd 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -159,9 +159,6 @@ dependencies { //此处以集成 5.1.2 版本为例 api 'cn.rongcloud.sdk:im_lib:5.1.3.10' // 即时通讯基础能力库 api 'cn.rongcloud.sdk:im_kit:5.1.3.10' // 即时通讯 UI 基础组件 - //此处以集成 5.1.2 版本为例 - api 'cn.rongcloud.sdk:im_lib:5.2.5' // 即时通讯基础能力库 - api 'cn.rongcloud.sdk:im_kit:5.2.5' // 即时通讯 UI 基础组件 //融云小视频模块 api 'cn.rongcloud.sdk:sight:5.2.5' api 'com.facebook.android:facebook-android-sdk:15.0.1' @@ -189,7 +186,6 @@ dependencies { implementation 'com.github.tajchert:WaitingDots:0.6.1' //悬浮窗 api 'com.github.princekin-f:EasyFloat:2.0.4' + api files('libs/Msc.jar') - -// api project(path: ':recognizer') } diff --git a/common/libs/Msc.jar b/common/libs/Msc.jar new file mode 100644 index 000000000..fe502fb3e Binary files /dev/null and b/common/libs/Msc.jar differ diff --git a/common/libs/arm64-v8a/libmsc.so b/common/libs/arm64-v8a/libmsc.so new file mode 100644 index 000000000..6077a8185 Binary files /dev/null and b/common/libs/arm64-v8a/libmsc.so differ diff --git a/common/libs/armeabi-v7a/libmsc.so b/common/libs/armeabi-v7a/libmsc.so new file mode 100644 index 000000000..1739ec3df Binary files /dev/null and b/common/libs/armeabi-v7a/libmsc.so differ diff --git a/common/src/main/java/com/yunbao/common/manager/imrongcloud/RongcloudIMManager.java b/common/src/main/java/com/yunbao/common/manager/imrongcloud/RongcloudIMManager.java index 4a620249e..c4a4f656b 100644 --- a/common/src/main/java/com/yunbao/common/manager/imrongcloud/RongcloudIMManager.java +++ b/common/src/main/java/com/yunbao/common/manager/imrongcloud/RongcloudIMManager.java @@ -16,6 +16,7 @@ import com.yunbao.common.CommonAppConfig; import com.yunbao.common.bean.IMLoginModel; import com.yunbao.common.event.RongIMConnectionStatusEvent; import com.yunbao.common.manager.IMLoginManager; +import com.yunbao.common.views.weight.Recognizer; import org.greenrobot.eventbus.EventBus; @@ -60,7 +61,7 @@ public class RongcloudIMManager { Log.e(CLASSNAME, "initRongIM:"); initPhotoGlide(); //初始化科大讯飞语音转文字 -// Recognizer.setAppId("af2efca9"); + Recognizer.setAppId("af2efca9"); } private static RongIMClient.OnReceiveMessageWrapperListener mListener; diff --git a/common/src/main/java/com/yunbao/common/views/weight/IRecognizedResult.java b/common/src/main/java/com/yunbao/common/views/weight/IRecognizedResult.java new file mode 100644 index 000000000..602840467 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/views/weight/IRecognizedResult.java @@ -0,0 +1,7 @@ +package com.yunbao.common.views.weight; + +/** Created by zwfang on 16/11/9. */ +public interface IRecognizedResult { + void onResult(String data); + +} diff --git a/common/src/main/java/com/yunbao/common/views/weight/Recognizer.java b/common/src/main/java/com/yunbao/common/views/weight/Recognizer.java new file mode 100644 index 000000000..1a528aa90 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/views/weight/Recognizer.java @@ -0,0 +1,362 @@ +package com.yunbao.common.views.weight; + +import android.content.Context; +import android.graphics.drawable.AnimationDrawable; +import android.os.Bundle; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.Toast; + +import com.iflytek.cloud.ErrorCode; +import com.iflytek.cloud.InitListener; +import com.iflytek.cloud.RecognizerListener; +import com.iflytek.cloud.RecognizerResult; +import com.iflytek.cloud.SpeechConstant; +import com.iflytek.cloud.SpeechError; +import com.iflytek.cloud.SpeechRecognizer; +import com.iflytek.cloud.SpeechUtility; +import com.yunbao.common.R; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; + +import java.util.Locale; +import java.util.Random; + + +public class Recognizer extends RelativeLayout implements RecognizerListener { + private static final String TAG = "Recognizer"; + + private ImageView imgMic; + + private Random random; + private IRecognizedResult mResultCallBack; + private SpeechRecognizer mIat = null; + private AnimationDrawable animStart; + private AnimationDrawable animEnd; + private static String mAppId; + + /** + * 开发者可以通过此接口设置自己从科大讯飞官网申请的 appId。 此方法可以在 SDK init 之后调用。 + * + *
注意: appid 必须和下载的SDK保持一致,否则会出现10407错误
+ *
+ * @param appId 自定义的 appId
+ */
+ public static void setAppId(String appId) {
+ mAppId = appId;
+ }
+
+ public Recognizer(Context context) {
+ super(context);
+ initViews();
+ }
+
+ public Recognizer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initViews();
+ }
+
+ private void initViews() {
+ setClickable(true);
+ setBackgroundColor(getResources().getColor(R.color.white));
+ RelativeLayout recognizerContainer =
+ (RelativeLayout)
+ LayoutInflater.from(getContext())
+ .inflate(R.layout.rc_view_recognizer, null);
+ View rlMic = recognizerContainer.findViewById(R.id.rl_mic);
+ rlMic.setOnClickListener(
+ new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (mIat == null || !mIat.isListening()) {
+ startRecognize();
+ } else {
+ reset();
+ }
+ }
+ });
+ imgMic = (ImageView) recognizerContainer.findViewById(R.id.img_mic);
+
+
+ addView(recognizerContainer);
+ random = new Random();
+ String params = SpeechConstant.APPID + "=" + mAppId;
+ SpeechUtility.createUtility(getContext().getApplicationContext(), params);
+ }
+
+ /**
+ * 初始化监听器。
+ */
+ private static InitListener mInitListener =
+ new InitListener() {
+
+ @Override
+ public void onInit(int code) {
+ Log.e(TAG, "onInit " + code);
+ }
+ };
+
+ public void startRecognize() {
+ if (null == mIat) {
+ mIat = SpeechRecognizer.createRecognizer(getContext(), mInitListener);
+ }
+ if (mIat.isListening()) {
+ return;
+ }
+ setParam();
+ int ret = mIat.startListening(this);
+ if (ret != ErrorCode.SUCCESS) {
+ Log.e(TAG, "startRecognize ret error " + ret);
+ }
+ }
+
+ /**
+ * 参数设置,设置听写参数,详见《科大讯飞MSC API手册(Android)》SpeechConstant类
+ *
+ * @param
+ * @return
+ */
+ private void setParam() {
+ // 清空参数
+ mIat.setParameter(SpeechConstant.PARAMS, null);
+
+ // 设置听写引擎
+ mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
+ // 设置返回结果格式
+ mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");
+
+ mIat.setParameter(SpeechConstant.DOMAIN, "iat");
+ if ("zh".equals(Locale.getDefault().getLanguage().toLowerCase())) {
+ mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
+ mIat.setParameter(SpeechConstant.ACCENT, "mandarin ");
+ } else {
+ mIat.setParameter(SpeechConstant.LANGUAGE, "en_us");
+ }
+ // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
+ mIat.setParameter(SpeechConstant.VAD_BOS, "4000");
+ // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
+ mIat.setParameter(SpeechConstant.VAD_EOS, "1000");
+ // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
+ mIat.setParameter(SpeechConstant.ASR_PTT, "1");
+ }
+
+ private void setRandomImageResource() {
+ int num = random.nextInt(3) + 1;
+ switch (num) {
+ case 1:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_01);
+ break;
+ case 2:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_02);
+ break;
+ default:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_03);
+ break;
+ }
+ }
+
+ private void changeVolume(int volume) {
+ if (null != imgMic) {
+ switch (volume / 2) {
+ case 0:
+ setRandomImageResource();
+ break;
+ case 1:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_02);
+ break;
+ case 2:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_03);
+ break;
+ case 3:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_04);
+ break;
+ case 4:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_05);
+ break;
+ case 5:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_06);
+ break;
+ case 6:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_07);
+ break;
+ case 7:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_08);
+ break;
+ case 8:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_09);
+ break;
+ case 9:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_10);
+ break;
+ case 10:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_11);
+ break;
+ case 11:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_12);
+ break;
+ case 12:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_13);
+ break;
+ default:
+ imgMic.setImageResource(R.mipmap.rc_recognize_volume_14);
+ break;
+ }
+ }
+ }
+
+ private void endOfSpeech() {
+ if (null == imgMic) return;
+ imgMic.setImageResource(R.drawable.rc_anim_speech_end);
+ animEnd = (AnimationDrawable) imgMic.getDrawable();
+ imgMic.clearAnimation();
+ animEnd.start();
+ }
+
+ private void beginOfSpeech() {
+ if (null == imgMic) return;
+ imgMic.setImageResource(R.drawable.rc_anim_speech_start);
+ animStart = (AnimationDrawable) imgMic.getDrawable();
+ imgMic.clearAnimation();
+ animStart.start();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (null != mIat) {
+ mIat.cancel();
+ mIat.destroy();
+ mIat = null;
+ }
+ if (null != mResultCallBack) {
+ mResultCallBack = null;
+ }
+ if (animEnd != null) {
+ animEnd.stop();
+ animEnd = null;
+ }
+ if (animStart != null) {
+ animStart.stop();
+ animEnd = null;
+ }
+ mInitListener = null;
+ }
+
+ private void printResult(RecognizerResult result) {
+ String json = result.getResultString();
+ String text = parseRecognizeResult(result);
+ Log.e(TAG, "printResult " + text);
+ try {
+ JSONObject obj = new JSONObject(json);
+ boolean isLast = obj.getBoolean("ls");
+ if (isLast) {
+ endOfSpeech();
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ if (mResultCallBack != null) {
+ mResultCallBack.onResult(text);
+ }
+ }
+
+ @Override
+ public void onResult(RecognizerResult recognizerResult, boolean b) {
+ printResult(recognizerResult);
+ if (imgMic != null) {
+ imgMic.setImageResource(R.mipmap.rc_recognize_disable);
+ }
+ }
+
+ @Override
+ public void onError(SpeechError speechError) {
+ if (speechError.getErrorCode() == ErrorCode.ERROR_NO_NETWORK) {
+ Toast.makeText(
+ getContext(),
+ getContext().getString(R.string.load_failure),
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+ if (imgMic != null) {
+ imgMic.setImageResource(R.mipmap.rc_recognize_disable);
+ }
+ }
+
+ @Override
+ public void onEvent(int eventType, int i1, int i2, Bundle bundle) {
+ Log.e(TAG, "RecognizerView onEvent eventType: " + eventType);
+ }
+
+ @Override
+ public void onVolumeChanged(int volume, byte[] bytes) {
+ changeVolume(volume);
+ }
+
+ @Override
+ public void onBeginOfSpeech() {
+ Log.e(TAG, "RecognizerView onBeginOfSpeech");
+ beginOfSpeech();
+ }
+
+ @Override
+ public void onEndOfSpeech() {
+ Log.e(TAG, "RecognizerView onEndOfSpeech");
+ endOfSpeech();
+ }
+
+ public void setCallBack(IRecognizedResult resultCallBack) {
+ mResultCallBack = resultCallBack;
+ }
+
+ private void reset() {
+ if (null != mIat) {
+ mIat.cancel();
+ mIat.destroy();
+ mIat = null;
+ }
+ if (null != animEnd) {
+ animEnd.stop();
+ animEnd = null;
+ }
+ if (animStart != null) {
+ animStart.stop();
+ animStart = null;
+ }
+ if (imgMic != null) {
+ imgMic.setImageResource(R.mipmap.rc_recognize_disable);
+ }
+ }
+
+ public String parseRecognizeResult(RecognizerResult results) {
+ StringBuilder ret = new StringBuilder();
+ try {
+ JSONTokener jsonTokener = new JSONTokener(results.getResultString());
+ JSONObject jsonObject = new JSONObject(jsonTokener);
+
+ JSONArray words = jsonObject.getJSONArray("ws");
+ for (int i = 0; i < words.length(); i++) {
+ // 转写结果词,默认使用第一个结果
+ JSONArray items = words.getJSONObject(i).getJSONArray("cw");
+ JSONObject obj = items.getJSONObject(0);
+ ret.append(obj.getString("w"));
+ // 如果需要多候选结果,解析数组其他字段
+ // for(int j = 0; j < items.length(); j++)
+ // {
+ // JSONObject obj = items.getJSONObject(j);
+ // ret.append(obj.getString("w"));
+ // }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return ret.toString();
+ }
+}
diff --git a/common/src/main/res/drawable/rc_anim_speech_end.xml b/common/src/main/res/drawable/rc_anim_speech_end.xml
new file mode 100644
index 000000000..302e3f040
--- /dev/null
+++ b/common/src/main/res/drawable/rc_anim_speech_end.xml
@@ -0,0 +1,35 @@
+
+