语音听写

This commit is contained in:
18401019693 2022-10-20 17:49:04 +08:00
parent 3c6b4d13a9
commit f25f61b78c
35 changed files with 503 additions and 78 deletions

View File

@ -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')
}

BIN
common/libs/Msc.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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;

View File

@ -0,0 +1,7 @@
package com.yunbao.common.views.weight;
/** Created by zwfang on 16/11/9. */
public interface IRecognizedResult {
void onResult(String data);
}

View File

@ -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 之后调用
*
* <p>注意 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();
}
}

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item android:drawable="@mipmap/rc_recognize_volume_01"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_02"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_03"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_04"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_05"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_06"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_07"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_08"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_09"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_10"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_11"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_12"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_13"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_14"
android:duration="50"/>
<item android:drawable="@mipmap/rc_recognize_volume_blue"
android:duration="100"/>
</animation-list>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item android:drawable="@mipmap/rc_recognize_volume_10"
android:duration="100"/>
<item android:drawable="@mipmap/rc_recognize_volume_11"
android:duration="100"/>
<item android:drawable="@mipmap/rc_recognize_volume_12"
android:duration="100"/>
<item android:drawable="@mipmap/rc_recognize_volume_13"
android:duration="100"/>
<item android:drawable="@mipmap/rc_recognize_volume_14"
android:duration="100"/>
<item android:drawable="@mipmap/rc_recognize_volume_blue"
android:duration="100"/>
</animation-list>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/white"/>
</shape>
</item>
<item android:state_pressed="false">
<shape android:shape="rectangle">
<solid android:color="@color/white"/>
</shape>
</item>
</selector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/rc_recognizer_voice_hover" android:state_pressed="true"/>
<item android:drawable="@mipmap/rc_recognizer_voice"/>
</selector>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/rl_mic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="@mipmap/rc_recognize_bg_mic">
<ImageView
android:id="@+id/img_mic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/rc_recognize_volume_grey" />
</RelativeLayout>
</RelativeLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -470,6 +470,12 @@ public class MainActivity extends AbsActivity implements MainAppBarLayoutListene
//获取指导员账号
ConversationIMListManager.get(this).getUserInstructor(this);
checkVersion();
// new Handler().postDelayed(new Runnable() {
// @Override
// public void run() {
// startActivity(new Intent(MainActivity.this,TestActivity.class));
// }
// },1000);
}
/**

View File

@ -1,84 +1,35 @@
package com.yunbao.main.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.text.SpannableStringBuilder;
import android.widget.TextView;
import com.tencent.live2.V2TXLiveDef;
import com.tencent.live2.V2TXLivePlayer;
import com.tencent.live2.V2TXLivePlayerObserver;
import com.tencent.live2.impl.V2TXLivePlayerImpl;
import com.tencent.rtmp.ui.TXCloudVideoView;
import androidx.appcompat.app.AppCompatActivity;
import com.yunbao.common.views.weight.IRecognizedResult;
import com.yunbao.common.views.weight.Recognizer;
import com.yunbao.main.R;
public class TestActivity extends AppCompatActivity {
private TXCloudVideoView mVideoView;
private V2TXLivePlayer mPlayer;
String TAG = "tag";
private TextView contextLayout;
private Recognizer recognizer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mVideoView = (TXCloudVideoView) findViewById(R.id.video_view);
mPlayer = new V2TXLivePlayerImpl(getApplicationContext());
mVideoView = (TXCloudVideoView) findViewById(R.id.video_view);
mPlayer.setRenderView(mVideoView);
mPlayer.setObserver(new V2TXLivePlayerObserver() {
contextLayout = findViewById(R.id.context_layout);
recognizer = findViewById(R.id.recognizer);
SpannableStringBuilder builder = new SpannableStringBuilder();
recognizer.setCallBack(new IRecognizedResult() {
@Override
public void onError(V2TXLivePlayer player, int code, String msg, Bundle extraInfo) {
Log.d(TAG, "[Player] onError: player-" + player + " code-" + code + " msg-" + msg + " info-" + extraInfo);
public void onResult(String data) {
builder.append(data);
contextLayout.setText(builder);
}
@Override
public void onVideoPlayStatusUpdate(V2TXLivePlayer player, V2TXLiveDef.V2TXLivePlayStatus status, V2TXLiveDef.V2TXLiveStatusChangeReason reason, Bundle bundle) {
Log.d(TAG, "[Player] onVideoPlayStatusUpdate: player-" + player + ", status-" + status + ", reason-" + reason);
}
@Override
public void onWarning(V2TXLivePlayer v2TXLivePlayer, int i, String s, Bundle bundle) {
Log.d(TAG, "[Player] Override: player-" + v2TXLivePlayer + ", i-" + i + ", s-" + s);
}
@Override
public void onRenderVideoFrame(V2TXLivePlayer player, V2TXLiveDef.V2TXLiveVideoFrame v2TXLiveVideoFrame) {
super.onRenderVideoFrame(player, v2TXLiveVideoFrame);
Log.d(TAG, "[Player] onRenderVideoFrame: player-" + player + ", v2TXLiveVideoFrame-" + v2TXLiveVideoFrame);
}
});
int result = mPlayer.startPlay("http://sylive.shayucm.com/live/31754_1631600921.flv");
Log.d(TAG, "startPlay : " + result);
// if (TextUtils.isEmpty(url)) {
// return;
// }
// int playType = -1;
// if (url.startsWith("rtmp://")) {
// playType = TXLivePlayer.PLAY_TYPE_LIVE_RTMP;
// } else if (url.endsWith(".flv")) {
// playType = TXLivePlayer.PLAY_TYPE_LIVE_FLV;
// } else if (url.endsWith(".m3u8")) {
// playType = TXLivePlayer.PLAY_TYPE_VOD_HLS;
// } else if (url.endsWith(".mp4")) {
// playType = TXLivePlayer.PLAY_TYPE_VOD_MP4;
// }
// if (playType == -1) {
// ToastUtil.show(R.string.live_play_error_2);
// return;
// }
// if (mPlayer != null) {
// int result = mPlayer.startPlay(url);
// if (result == 0) {
// mStarted = true;
// mUrl = url;
// mPlayType = playType;
// }
// }
// L.e(TAG, "play----url--->" + url);
}
}

View File

@ -1,15 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|left"
android:background="@color/gray3">
android:background="@color/white"
<com.tencent.rtmp.ui.TXCloudVideoView
android:id="@+id/video_view"
android:orientation="vertical">
<TextView
android:id="@+id/context_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"/>
android:layout_height="0dp"
android:layout_weight="1" />
<com.yunbao.common.views.weight.Recognizer
android:id="@+id/recognizer"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center" />
</LinearLayout>