mirror of
https://github.com/modelscope/FunASR
synced 2025-09-15 14:48:36 +08:00
change send data size (#1014)
* change send data size * 增加菜单栏和APK下载地址 * 忽略SSL证书验证
This commit is contained in:
parent
0dd01a880b
commit
de3f9462e0
@ -10,9 +10,9 @@
|
|||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@drawable/logo"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@drawable/logo"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.AndroidClient"
|
android:theme="@style/Theme.AndroidClient"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
|
|||||||
@ -2,18 +2,25 @@ package com.yeyupiaoling.androidclient;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.media.AudioFormat;
|
import android.media.AudioFormat;
|
||||||
import android.media.AudioRecord;
|
import android.media.AudioRecord;
|
||||||
import android.media.MediaRecorder;
|
import android.media.MediaRecorder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
|
|
||||||
@ -21,8 +28,6 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
@ -32,8 +37,15 @@ import okio.ByteString;
|
|||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
public static final String TAG = MainActivity.class.getSimpleName();
|
public static final String TAG = MainActivity.class.getSimpleName();
|
||||||
// WebSocket地址,如果服务端没有使用SSL,请使用ws://
|
// WebSocket地址
|
||||||
public static final String ASR_HOST = "wss://192.168.0.1:10095";
|
public String ASR_HOST = "";
|
||||||
|
// 发送的JSON数据
|
||||||
|
public static final String MODE = "2pass";
|
||||||
|
public static final String CHUNK_SIZE = "5, 10, 5";
|
||||||
|
public static final int CHUNK_INTERVAL = 10;
|
||||||
|
public static final int SEND_SIZE = 1920;
|
||||||
|
// 热词
|
||||||
|
private String hotWords = "阿里巴巴 达摩院 夜雨飘零";
|
||||||
// 采样率
|
// 采样率
|
||||||
public static final int SAMPLE_RATE = 16000;
|
public static final int SAMPLE_RATE = 16000;
|
||||||
// 声道数
|
// 声道数
|
||||||
@ -42,10 +54,10 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
public static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
|
public static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
|
||||||
private AudioRecord audioRecord;
|
private AudioRecord audioRecord;
|
||||||
private boolean isRecording = false;
|
private boolean isRecording = false;
|
||||||
private int minBufferSize;
|
|
||||||
private AudioView audioView;
|
private AudioView audioView;
|
||||||
private String allAsrText = "";
|
private String allAsrText = "";
|
||||||
private String asrText = "";
|
private String asrText = "";
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
// 控件
|
// 控件
|
||||||
private Button recordBtn;
|
private Button recordBtn;
|
||||||
private TextView resultText;
|
private TextView resultText;
|
||||||
@ -60,8 +72,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
if (!hasPermission()) {
|
if (!hasPermission()) {
|
||||||
requestPermission();
|
requestPermission();
|
||||||
}
|
}
|
||||||
// 录音参数
|
|
||||||
minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL, AUDIO_FORMAT);
|
|
||||||
// 显示识别结果控件
|
// 显示识别结果控件
|
||||||
resultText = findViewById(R.id.result_text);
|
resultText = findViewById(R.id.result_text);
|
||||||
// 显示录音状态控件
|
// 显示录音状态控件
|
||||||
@ -71,22 +81,100 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
recordBtn = findViewById(R.id.record_button);
|
recordBtn = findViewById(R.id.record_button);
|
||||||
recordBtn.setOnTouchListener((v, event) -> {
|
recordBtn.setOnTouchListener((v, event) -> {
|
||||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||||
isRecording = false;
|
if (!ASR_HOST.equals("")) {
|
||||||
stopRecording();
|
isRecording = false;
|
||||||
recordBtn.setText("按下录音");
|
stopRecording();
|
||||||
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
recordBtn.setText("按下录音");
|
||||||
if (webSocket != null){
|
}
|
||||||
webSocket.cancel();
|
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
webSocket = null;
|
if (!ASR_HOST.equals("")) {
|
||||||
|
allAsrText = "";
|
||||||
|
asrText = "";
|
||||||
|
isRecording = true;
|
||||||
|
startRecording();
|
||||||
|
recordBtn.setText("录音中...");
|
||||||
}
|
}
|
||||||
allAsrText = "";
|
|
||||||
asrText = "";
|
|
||||||
isRecording = true;
|
|
||||||
startRecording();
|
|
||||||
recordBtn.setText("录音中...");
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
// 读取WebSocket地址
|
||||||
|
sharedPreferences = getSharedPreferences("FunASR", MODE_PRIVATE);
|
||||||
|
String uri = sharedPreferences.getString("uri", "");
|
||||||
|
if (uri.equals("")) {
|
||||||
|
showUriInput();
|
||||||
|
} else {
|
||||||
|
ASR_HOST = uri;
|
||||||
|
}
|
||||||
|
// 读取热词
|
||||||
|
String hotWords = sharedPreferences.getString("hotwords", "");
|
||||||
|
if (!hotWords.equals("")) {
|
||||||
|
this.hotWords = hotWords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
getMenuInflater().inflate(R.menu.menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
if (id == R.id.change_uri) {
|
||||||
|
showUriInput();
|
||||||
|
return true;
|
||||||
|
} else if (id == R.id.change_hotwords) {
|
||||||
|
showHotWordsInput();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示WebSocket地址输入框
|
||||||
|
private void showUriInput() {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
|
||||||
|
builder.setTitle("请输入WebSocket地址:");
|
||||||
|
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.dialog_input_uri, null);
|
||||||
|
final EditText input = view.findViewById(R.id.uri_edit_text);
|
||||||
|
if (!ASR_HOST.equals("")) {
|
||||||
|
input.setText(ASR_HOST);
|
||||||
|
}
|
||||||
|
builder.setView(view);
|
||||||
|
builder.setPositiveButton("确定", (dialog, id) -> {
|
||||||
|
ASR_HOST = input.getText().toString();
|
||||||
|
if (!ASR_HOST.equals("")) {
|
||||||
|
Toast.makeText(MainActivity.this, "WebSocket地址:" + ASR_HOST, Toast.LENGTH_SHORT).show();
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString("uri", ASR_HOST);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog dialog = builder.create();
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示热词输入框
|
||||||
|
private void showHotWordsInput() {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
|
||||||
|
builder.setTitle("请输入热词:");
|
||||||
|
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.dialog_input_hotwords, null);
|
||||||
|
final EditText input = view.findViewById(R.id.hotwords_edit_text);
|
||||||
|
if (!this.hotWords.equals("")) {
|
||||||
|
input.setText(this.hotWords);
|
||||||
|
}
|
||||||
|
builder.setView(view);
|
||||||
|
builder.setPositiveButton("确定", (dialog, id) -> {
|
||||||
|
String hotwords = input.getText().toString();
|
||||||
|
if (!hotwords.equals("")) {
|
||||||
|
this.hotWords = hotwords;
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString("hotwords", hotwords);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog dialog = builder.create();
|
||||||
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始录音
|
// 开始录音
|
||||||
@ -94,12 +182,12 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
// 准备录音器
|
// 准备录音器
|
||||||
try {
|
try {
|
||||||
// 确保有权限
|
// 确保有权限
|
||||||
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||||
requestPermission();
|
requestPermission();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 创建录音器
|
// 创建录音器
|
||||||
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, CHANNEL, AUDIO_FORMAT, minBufferSize);
|
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, CHANNEL, AUDIO_FORMAT, SEND_SIZE);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -127,14 +215,12 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
// 读取录音数据
|
// 读取录音数据
|
||||||
private void setAudioData() throws Exception {
|
private void setAudioData() throws Exception {
|
||||||
// 如果使用正常的wss,可以去掉这个
|
|
||||||
HostnameVerifier hostnameVerifier = (hostname, session) -> {
|
|
||||||
// 总是返回true,表示不验证域名
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
// 建立WebSocket连接
|
// 建立WebSocket连接
|
||||||
OkHttpClient client = new OkHttpClient.Builder()
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
.hostnameVerifier(hostnameVerifier)
|
// 忽略验证证书
|
||||||
|
.sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getX509TrustManager())
|
||||||
|
// 不验证域名
|
||||||
|
.hostnameVerifier(SSLSocketClient.getHostnameVerifier())
|
||||||
.build();
|
.build();
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(ASR_HOST)
|
.url(ASR_HOST)
|
||||||
@ -145,6 +231,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
public void onOpen(@NonNull WebSocket webSocket, @NonNull Response response) {
|
public void onOpen(@NonNull WebSocket webSocket, @NonNull Response response) {
|
||||||
// 连接成功时的处理
|
// 连接成功时的处理
|
||||||
Log.d(TAG, "WebSocket连接成功");
|
Log.d(TAG, "WebSocket连接成功");
|
||||||
|
runOnUiThread(() -> Toast.makeText(MainActivity.this, "WebSocket连接成功", Toast.LENGTH_SHORT).show());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -189,15 +276,16 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
public void onFailure(@NonNull WebSocket webSocket, @NonNull Throwable t, Response response) {
|
public void onFailure(@NonNull WebSocket webSocket, @NonNull Throwable t, Response response) {
|
||||||
// 连接失败时的处理
|
// 连接失败时的处理
|
||||||
Log.d(TAG, "WebSocket连接失败: " + t + ": " + response);
|
Log.d(TAG, "WebSocket连接失败: " + t + ": " + response);
|
||||||
|
runOnUiThread(() -> Toast.makeText(MainActivity.this, "WebSocket连接失败:" + t, Toast.LENGTH_SHORT).show());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
String message = getMessage("2pass", "5, 10, 5", 10, true);
|
String message = getMessage(true);
|
||||||
webSocket.send(message);
|
webSocket.send(message);
|
||||||
|
|
||||||
audioRecord.startRecording();
|
audioRecord.startRecording();
|
||||||
byte[] bytes = new byte[minBufferSize];
|
byte[] bytes = new byte[SEND_SIZE];
|
||||||
while (isRecording) {
|
while (isRecording) {
|
||||||
int readSize = audioRecord.read(bytes, 0, minBufferSize);
|
int readSize = audioRecord.read(bytes, 0, SEND_SIZE);
|
||||||
if (readSize > 0) {
|
if (readSize > 0) {
|
||||||
ByteString byteString = ByteString.of(bytes);
|
ByteString byteString = ByteString.of(bytes);
|
||||||
webSocket.send(byteString);
|
webSocket.send(byteString);
|
||||||
@ -211,20 +299,19 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送第一步的JSON数据
|
// 发送第一步的JSON数据
|
||||||
public String getMessage(String mode, String strChunkSize, int chunkInterval, boolean isSpeaking) {
|
public String getMessage(boolean isSpeaking) {
|
||||||
try {
|
try {
|
||||||
JSONObject obj = new JSONObject();
|
JSONObject obj = new JSONObject();
|
||||||
obj.put("mode", mode);
|
obj.put("mode", MODE);
|
||||||
JSONArray array = new JSONArray();
|
JSONArray array = new JSONArray();
|
||||||
String[] chunkList = strChunkSize.split(",");
|
String[] chunkList = CHUNK_SIZE.split(",");
|
||||||
for (String s : chunkList) {
|
for (String s : chunkList) {
|
||||||
array.put(Integer.valueOf(s.trim()));
|
array.put(Integer.valueOf(s.trim()));
|
||||||
}
|
}
|
||||||
obj.put("chunk_size", array);
|
obj.put("chunk_size", array);
|
||||||
obj.put("chunk_interval", chunkInterval);
|
obj.put("chunk_interval", CHUNK_INTERVAL);
|
||||||
obj.put("wav_name", "default");
|
obj.put("wav_name", "default");
|
||||||
// 热词
|
obj.put("hotwords", hotWords);
|
||||||
obj.put("hotwords", "阿里巴巴 达摩院");
|
|
||||||
obj.put("wav_format", "pcm");
|
obj.put("wav_format", "pcm");
|
||||||
obj.put("is_speaking", isSpeaking);
|
obj.put("is_speaking", isSpeaking);
|
||||||
return obj.toString();
|
return obj.toString();
|
||||||
@ -236,13 +323,13 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
// 检查权限
|
// 检查权限
|
||||||
private boolean hasPermission() {
|
private boolean hasPermission() {
|
||||||
return checkSelfPermission(android.Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED &&
|
return checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED &&
|
||||||
checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求权限
|
// 请求权限
|
||||||
private void requestPermission() {
|
private void requestPermission() {
|
||||||
requestPermissions(new String[]{android.Manifest.permission.RECORD_AUDIO,
|
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO,
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
|
Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package com.yeyupiaoling.androidclient;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
public class SSLSocketClient {
|
||||||
|
//获取SSLSocketFactory
|
||||||
|
public static SSLSocketFactory getSSLSocketFactory() {
|
||||||
|
try {
|
||||||
|
SSLContext sslContext = SSLContext.getInstance("SSL");
|
||||||
|
sslContext.init(null, getTrustManager(), new SecureRandom());
|
||||||
|
return sslContext.getSocketFactory();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取X509TrustManager
|
||||||
|
public static X509TrustManager getX509TrustManager() {
|
||||||
|
X509TrustManager x509TrustManager = new X509TrustManager() {
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return new X509Certificate[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return x509TrustManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取TrustManager
|
||||||
|
private static TrustManager[] getTrustManager() {
|
||||||
|
TrustManager[] trustAllCerts = new TrustManager[]{
|
||||||
|
new X509TrustManager() {
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return new X509Certificate[]{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return trustAllCerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取HostnameVerifier
|
||||||
|
public static HostnameVerifier getHostnameVerifier() {
|
||||||
|
HostnameVerifier hostnameVerifier = (s, sslSession) -> true;
|
||||||
|
return hostnameVerifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<stroke android:width="1dp" android:color="#000000" />
|
||||||
|
<padding android:left="5dp" android:top="5dp" android:right="5dp" android:bottom="5dp" />
|
||||||
|
</shape>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/hotwords_edit_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="200dp"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:background="@drawable/edittext_border"
|
||||||
|
android:minLines="3"
|
||||||
|
android:gravity="top"
|
||||||
|
android:hint="每个热词用空格隔开" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/uri_edit_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:background="@drawable/edittext_border"
|
||||||
|
android:hint="wss://" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/change_uri"
|
||||||
|
android:title="服务地址" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/change_hotwords"
|
||||||
|
android:title="热词" />
|
||||||
|
</menu>
|
||||||
BIN
funasr/runtime/android/images/QRcode.png
Normal file
BIN
funasr/runtime/android/images/QRcode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 44 KiB |
BIN
funasr/runtime/android/images/image1.png
Normal file
BIN
funasr/runtime/android/images/image1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
funasr/runtime/android/images/image2.png
Normal file
BIN
funasr/runtime/android/images/image2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
BIN
funasr/runtime/android/images/image3.png
Normal file
BIN
funasr/runtime/android/images/image3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 253 KiB |
@ -2,12 +2,19 @@
|
|||||||
|
|
||||||
先说明,本项目是使用WebSocket连接服务器的语音识别服务,并不是将FunASR部署到Android里,服务启动方式请查看文档[SDK_advanced_guide_online_zh.md](https://github.com/alibaba-damo-academy/FunASR/blob/main/funasr/runtime/docs/SDK_advanced_guide_online_zh.md)。
|
先说明,本项目是使用WebSocket连接服务器的语音识别服务,并不是将FunASR部署到Android里,服务启动方式请查看文档[SDK_advanced_guide_online_zh.md](https://github.com/alibaba-damo-academy/FunASR/blob/main/funasr/runtime/docs/SDK_advanced_guide_online_zh.md)。
|
||||||
|
|
||||||
使用最新的 Android Studio 打开`AndroidClient`项目,运行即可,在运行之前还需要修改`ASR_HOST`参数,该参数是语音识别服务的WebSocket接口地址,需要修复为开发者自己的服务地址。
|
使用最新的 Android Studio 打开`AndroidClient`项目,运行即可。也可以直接下载[APK安装包](https://yeyupiaoling.cn/AndroidClient.apk)安装使用,或者使用手机扫码下载。
|
||||||
|
|
||||||
应用只有一个功能,按钮下开始识别,松开按钮结束识别。
|
<div align="center">
|
||||||
|
<img src="./images/QRcode.png" alt="APK安装包" width="300">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
应用只有一个功能,按钮下开始识别,松开按钮结束识别。第一次打开应用需要设置WebSocket的地址,也可以在菜单栏修改,同时也可以在菜单栏修改热词。
|
||||||
|
|
||||||
应用效果图:
|
应用效果图:
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="./images/demo.png" alt="应用效果图" width="300">
|
<img src="./images/image1.png" alt="应用效果图" width="300">
|
||||||
|
<img src="./images/image2.png" alt="应用效果图" width="300">
|
||||||
|
<img src="./images/image3.png" alt="应用效果图" width="300">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user