完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
上位机是安卓机,下位机是51,上位机(语音识别出指令如开关灯)与下位机(接蓝牙模块BLE:CC2451)通过蓝牙通信进行控制。
初步设想是语音识别部分用科大讯飞的sdk,然后再找个开源的蓝牙通信Demo来进行二次开发,无奈本人小白,无安卓开发经验,java零基础,虽然论坛上有很多现成的蓝牙控制单片机的例子,但是好像没有语音识别这一部分的,做得很难受。 以下贴出我的进展图、App闪退错误代码,以及半成品Demo(只实现了语音识别部分),希望有大牛指导一下。 开发环境:Android Studio 2.1.3 Gradle版本:com.android.tools.build:gradle:2.1.3 SDK版本:android-sdk_r24.4.1-windows JDK版本:jdk1.8.0_201 Compile Sdk Version:API 25 Build Tools Version:28.0.3 android:icon="@mipmap/ic_launcher" android:label="智能家居控制面板" android:supportsRtl="true" android:theme="@style/AppTheme"> android:value="@integer/google_play_services_version" /> MainActivitiy.java package com.example.luoyn.speechdemo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.net.Uri; import android.os.Environment; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import android.os.Handler; import com.google.android.gms.appindexing.Action; import com.google.android.gms.appindexing.AppIndex; import com.google.android.gms.common.api.GoogleApiClient; 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.iflytek.cloud.ui.RecognizerDialog; import com.iflytek.cloud.ui.RecognizerDialogListener; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.UUID; public class MainActivity extends AppCompatActivity implements View.OnClickListener { //显示听写结果 private TextView textView; //语音听写对象 private SpeechRecognizer speechRecognizer; //语音听写UI private RecognizerDialog recognizerDialog; //是否显示听写UI private boolean isShowDialog = true; //缓存 private SharedPreferences sharedPreferences; //用hashmap存储听写结果 private HashMap //引擎类型(云端或本地) private String mEngineType = null; //函数返回值 private int ret = 0; private Toast toast; //插入部分-------------------------------------------------------------------------------------- public static final int REQUEST_BT_ENABLE_CODE = 200; public static final String BT_UUID = "00001101-0000-1000-8000-00805F9B34FB";//YahBoom_uuid private BluetoothAdapter mBluetoothAdapter;//蓝牙适配器 private BlueToothStateReceiver mReceiver;//广播接收器 private ConnectThread mConnectThread; //客户端线程 private AcceptThread mAcceptThread; //服务端线程 private RecyclerView mRecyclerView; private RvAdapter mRvAdapter; private RecyclerView mMessageView; private static MsgAdapter mMessageAdapter; private EditText inputEt; private static Handler mHandler = new Handler() { @Override public void dispatchMessage(Message msg) { mMessageAdapter.addMessage((String) msg.obj); } }; /** * ATTENTION: This was auto-generated to implement the App Indexing API. * See https://g.co/AppIndexing/AndroidStudio for more information. */ private GoogleApiClient client; //---------------------------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initDate(); //插入部分-------------------------------------------------------------------------------------- initUI(); registerRec(); //------------------------------------------------------------------------------------------ // ATTENTION: This was auto-generated to implement the App Indexing API. // See https://g.co/AppIndexing/AndroidStudio for more information. client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build(); } private void initDate() { //初始化sdk 将自己申请的appid放到下面 //此句代码应该放在application中的,这里为了方便就直接放代码中了 SpeechUtility.createUtility(this, "appid=5c6abcfc"); speechRecognizer = SpeechRecognizer.createRecognizer(this, initListener); recognizerDialog = new RecognizerDialog(this, initListener); sharedPreferences = getSharedPreferences(this.getPackageName(), Context.MODE_PRIVATE); toast = Toast.makeText(this, "", Toast.LENGTH_SHORT); //这里我直接将引擎类型设置为云端,因为本地需要下载讯飞语记,这里为了方便直接使用云端 //有需要的朋友可以加个单选框 让用户选择云端或本地 mEngineType = SpeechConstant.TYPE_CLOUD; } private void initView() { textView = (TextView) findViewById(R.id.tv); } //插入部分-------------------------------------------------------------------------------------- private void initUI() { findViewById(R.id.open).setOnClickListener(this); findViewById(R.id.close).setOnClickListener(this); findViewById(R.id.start).setOnClickListener(this); findViewById(R.id.stop).setOnClickListener(this); findViewById(R.id.send).setOnClickListener(this); inputEt = (EditText) findViewById(R.id.input); mRecyclerView = (RecyclerView) findViewById(R.id.devices); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRvAdapter = new RvAdapter(this); mRecyclerView.setAdapter(mRvAdapter); mRvAdapter.setOnItemClickListener(new RvAdapter.OnItemClickListener() { @Override public void onClick(BluetoothDevice device) { mConnectThread = new ConnectThread(device); mConnectThread.start(); } }); mMessageView = (RecyclerView) findViewById(R.id.msglist); mMessageView.setLayoutManager(new LinearLayoutManager(this)); mMessageAdapter = new MsgAdapter(this); mMessageView.setAdapter(mMessageAdapter); } private void openBT() { if (mBluetoothAdapter == null) { mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } //1.设备不支持蓝牙,结束应用 if (mBluetoothAdapter == null) { finish(); return; } //2.判断蓝牙是否打开 if (!mBluetoothAdapter.enable()) { //没打开请求打开 Intent btEnable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(btEnable, REQUEST_BT_ENABLE_CODE); } } private void registerRec() { //3.注册蓝牙广播 mReceiver = new BlueToothStateReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND);//搜多到蓝牙 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索结束 registerReceiver(mReceiver, filter); } @Override protected void onDestroy() { if (mReceiver != null) { unregisterReceiver(mReceiver); } super.onDestroy(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_BT_ENABLE_CODE) { if (resultCode == RESULT_OK) { //用户允许打开蓝牙 mMessageAdapter.addMessage("用户同意打开蓝牙"); } else if (resultCode == RESULT_CANCELED) { //用户取消打开蓝牙 mMessageAdapter.addMessage("用户拒绝打开蓝牙"); } } super.onActivityResult(requestCode, resultCode, data); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.open: openBT(); mMessageAdapter.addMessage("打开蓝牙"); if (mAcceptThread == null && mBluetoothAdapter != null) { mAcceptThread = new AcceptThread(); mAcceptThread.start(); mMessageAdapter.addMessage("启动服务线程"); } break; case R.id.close: mBluetoothAdapter.disable(); break; case R.id.start: if (mBluetoothAdapter != null) { mRvAdapter.clearDevices();//开始搜索前清空上一次的列表 mBluetoothAdapter.startDiscovery(); mMessageAdapter.addMessage("开始搜索蓝牙"); } else { openBT(); if (mBluetoothAdapter != null) { mRvAdapter.clearDevices();//开始搜索前清空上一次的列表 mBluetoothAdapter.startDiscovery(); mMessageAdapter.addMessage("开始搜索蓝牙"); } } break; case R.id.stop: if (mBluetoothAdapter != null && mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } break; case R.id.send: String msg = inputEt.getText().toString(); if (TextUtils.isEmpty(msg)) { Toast.makeText(this, "消息为空", Toast.LENGTH_SHORT).show(); return; } if (mConnectThread != null) {//证明我主动去链接别人了 mConnectThread.write(msg); } else if (mAcceptThread != null) { mAcceptThread.write(msg); } mMessageAdapter.addMessage("发送消息:" + msg); break; } } @Override public void onStart() { super.onStart(); // ATTENTION: This was auto-generated to implement the App Indexing API. // See https://g.co/AppIndexing/AndroidStudio for more information. client.connect(); Action viewAction = Action.newAction( Action.TYPE_VIEW, // TODO: choose an action type. "Main Page", // TODO: Define a title for the content shown. // TODO: If you have web page content that matches this app activity's content, // make sure this auto-generated web page URL is correct. // Otherwise, set the URL to null. Uri.parse("http://host/path"), // TODO: Make sure this auto-generated app URL is correct. Uri.parse("android-app://com.example.luoyn.speechdemo/http/host/path") ); AppIndex.AppIndexApi.start(client, viewAction); } @Override public void onStop() { super.onStop(); // ATTENTION: This was auto-generated to implement the App Indexing API. // See https://g.co/AppIndexing/AndroidStudio for more information. Action viewAction = Action.newAction( Action.TYPE_VIEW, // TODO: choose an action type. "Main Page", // TODO: Define a title for the content shown. // TODO: If you have web page content that matches this app activity's content, // make sure this auto-generated web page URL is correct. // Otherwise, set the URL to null. Uri.parse("http://host/path"), // TODO: Make sure this auto-generated app URL is correct. Uri.parse("android-app://com.example.luoyn.speechdemo/http/host/path") ); AppIndex.AppIndexApi.end(client, viewAction); client.disconnect(); } class BlueToothStateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(MainActivity.this, "触发广播", Toast.LENGTH_SHORT).show(); String action = intent.getAction(); switch (action) { case BluetoothDevice.ACTION_FOUND: BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); Toast.makeText(MainActivity.this, "找到设备" + device.getName(), Toast.LENGTH_SHORT).show(); if (mRvAdapter != null) { mRvAdapter.addDevice(device); } break; case BluetoothAdapter.ACTION_DISCOVERY_FINISHED: mMessageAdapter.addMessage("搜索结束"); break; } } } class ConnectThread extends Thread { private BluetoothDevice mDevice; private BluetoothSocket mSocket; private InputStream btIs; private OutputStream btOs; private boolean canRecv; private PrintWriter writer; public ConnectThread(BluetoothDevice device) { mDevice = device; canRecv = true; } @Override public void run() { if (mDevice != null) { try { //获取套接字 BluetoothSocket temp = mDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(BT_UUID)); //mDevice.createRfcommSocketToServiceRecord(UUID.fromString(BT_UUID));//sdk 2.3以下使用 mSocket = temp; //发起连接请求 if (mSocket != null) { mSocket.connect(); } sendHandlerMsg("连接 " + mDevice.getName() + "成功!"); //获取输入输出流 btIs = mSocket.getInputStream(); btOs = mSocket.getOutputStream(); //通讯-接收消息 BufferedReader reader = new BufferedReader(new InputStreamReader(btIs, "UTF-8")); String content = null; while (canRecv) { content = reader.readLine(); sendHandlerMsg("收到消息:" + content); } } catch (IOException e) { e.printStackTrace(); sendHandlerMsg("错误:" + e.getMessage()); } finally { try { if (mSocket != null) { mSocket.close(); } //btIs.close();//两个输出流都依赖socket,关闭socket即可 //btOs.close(); } catch (IOException e) { e.printStackTrace(); sendHandlerMsg("错误:" + e.getMessage()); } } } } private void sendHandlerMsg(String content) { Message msg = mHandler.obtainMessage(); msg.what = 1001; msg.obj = content; mHandler.sendMessage(msg); } public void write(String msg) { if (btOs != null) { try { if (writer == null) { writer = new PrintWriter(new OutputStreamWriter(btOs, "UTF-8"), true); } writer.println(msg); } catch (UnsupportedEncodingException e) { e.printStackTrace(); writer.close(); sendHandlerMsg("错误:" + e.getMessage()); } } } } class AcceptThread extends Thread { private BluetoothServerSocket mServerSocket; private BluetoothSocket mSocket; private InputStream btIs; private OutputStream btOs; private PrintWriter writer; private boolean canAccept; private boolean canRecv; public AcceptThread() { canAccept = true; canRecv = true; } @Override public void run() { try { //获取套接字 BluetoothServerSocket temp = mBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("TEST", UUID.fromString(BT_UUID)); mServerSocket = temp; //监听连接请求 -- 作为测试,只允许连接一个设备 if (mServerSocket != null) { // while (canAccept) { mSocket = mServerSocket.accept(); sendHandlerMsg("有客户端连接"); // } } //获取输入输出流 btIs = mSocket.getInputStream(); btOs = mSocket.getOutputStream(); //通讯-接收消息 BufferedReader reader = new BufferedReader(new InputStreamReader(btIs, "UTF-8")); String content = null; while (canRecv) { content = reader.readLine(); sendHandlerMsg("收到消息:" + content); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (mSocket != null) { mSocket.close(); } // btIs.close();//两个输出流都依赖socket,关闭socket即可 // btOs.close(); } catch (IOException e) { e.printStackTrace(); sendHandlerMsg("错误:" + e.getMessage()); } } } private void sendHandlerMsg(String content) { Message msg = mHandler.obtainMessage(); msg.what = 1001; msg.obj = content; mHandler.sendMessage(msg); } public void write(String msg) { if (btOs != null) { try { if (writer == null) { writer = new PrintWriter(new OutputStreamWriter(btOs, "UTF-8"), true); } writer.println(msg); } catch (UnsupportedEncodingException e) { e.printStackTrace(); writer.close(); sendHandlerMsg("错误:" + e.getMessage()); } } } } //---------------------------------------------------------------------------------------------- //开始听写 public void start(View view) { textView.setText(""); hashMap.clear(); setParams(); if (isShowDialog) { recognizerDialog.setListener(dialogListener); recognizerDialog.show(); } else { ret = speechRecognizer.startListening(recognizerListener); if (ret != ErrorCode.SUCCESS) { Log.e("tag", "听写失败,错误码" + ret); } } } //结束听写 public void stop(View view) { Toast.makeText(this, "停止听写", Toast.LENGTH_SHORT).show(); if (isShowDialog) { recognizerDialog.dismiss(); } else { speechRecognizer.stopListening(); } } //初始化监听器 private InitListener initListener = new InitListener() { @Override public void onInit(int i) { if (i != ErrorCode.SUCCESS) { Log.e("tag", "初始化失败,错误码" + i); } } }; //无UI监听器 private RecognizerListener recognizerListener = new RecognizerListener() { @Override public void onVolumeChanged(final int i, byte[] bytes) { Log.e("tag", "返回数据大小" + bytes.length); runOnUiThread(new Runnable() { @Override public void run() { toast.setText("当前音量" + i); } }); } @Override public void onBeginOfSpeech() { Log.e("tag", "开始说话"); } @Override public void onEndOfSpeech() { Log.e("tag", "结束说话"); } @Override public void onResult(RecognizerResult recognizerResult, boolean b) { if (recognizerResult != null) { Log.e("tag", "听写结果:" + recognizerResult.getResultString()); printResult(recognizerResult); } } @Override public void onError(SpeechError speechError) { Log.e("tag", "错误信息" + speechError.getPlainDescription(true)); } @Override public void onEvent(int i, int i1, int i2, Bundle bundle) { // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给威廉希尔官方网站 支持人员,可用于查询会话日志,定位出错原因 // 若使用本地能力,会话id为null // if (SpeechEvent.EVENT_SESSION_ID == eventType) { // String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID); // Log.d(TAG, "session id =" + sid); // } } }; //有UI监听器 private RecognizerDialogListener dialogListener = new RecognizerDialogListener() { @Override public void onResult(RecognizerResult recognizerResult, boolean b) { if (recognizerResult != null) { Log.e("tag", "听写结果:" + recognizerResult.getResultString()); printResult(recognizerResult); } } @Override public void onError(SpeechError speechError) { Log.e("tag", speechError.getPlainDescription(true)); } }; //输出结果,将返回的json字段解析并在textVie中显示 private void printResult(RecognizerResult results) { String text = JsonParser.parseIatResult(results.getResultString()); String sn = null; // 读取json结果中的sn字段 try { JSONObject resultJson = new JSONObject(results.getResultString()); sn = resultJson.optString("sn"); } catch (JSONException e) { e.printStackTrace(); } hashMap.put(sn, text); StringBuffer resultBuffer = new StringBuffer(); for (String key : hashMap.keySet()) { resultBuffer.append(hashMap.get(key)); } textView.setText(resultBuffer.toString()); } private void setParams() { //清空参数 speechRecognizer.setParameter(SpeechConstant.PARAMS, null); //设置引擎 speechRecognizer.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType); //设置返回数据类型 speechRecognizer.setParameter(SpeechConstant.RESULT_TYPE, "json"); //设置中文 普通话 speechRecognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn"); speechRecognizer.setParameter(SpeechConstant.ACCENT, "mandarin"); // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理 speechRecognizer.setParameter(SpeechConstant.VAD_BOS, sharedPreferences.getString("iat_vadbos_preference", "4000")); // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音 speechRecognizer.setParameter(SpeechConstant.VAD_EOS, sharedPreferences.getString("iat_vadeos_preference", "1000")); // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点 speechRecognizer.setParameter(SpeechConstant.ASR_PTT, sharedPreferences.getString("iat_punc_preference", "0")); // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 // 注:AUDIO_FORMAT参数语记需要更新版本才能生效 speechRecognizer.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); speechRecognizer.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav"); } } activity_main.xml android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:weightSum="1"> android:layout_width="match_parent" android:layout_height="36dp" android:background="#55cccccc" /> android:layout_height="wrap_content" android:orientation="horizontal"> android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="开始听写" android:onClick="start" /> android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="停止听写" android:onClick="stop" /> android:layout_width="match_parent" android:layout_height="wrap_content" android:weightSum="1"> android:layout_width="0dp" android:layout_height="wrap_content" android:onClick="led" android:text="灯开关" android:id="@+id/button1" android:layout_weight="0.5" /> android:layout_width="0dp" android:layout_height="wrap_content" android:onClick="fan" android:text="风扇开关" android:id="@+id/button2" android:layout_weight="0.5" /> android:layout_width="match_parent" android:layout_height="wrap_content" android:weightSum="1"> android:layout_width="0dp" android:layout_height="wrap_content" android:onClick="open" android:text="打开蓝牙" android:id="@+id/open" android:layout_weight="0.50" /> android:layout_width="0dp" android:layout_height="wrap_content" android:onClick="close" android:text="关闭蓝牙" android:id="@+id/close" android:layout_weight="0.50" /> android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"> android:layout_width="0dp" android:layout_height="wrap_content" android:text="搜索设备" android:id="@+id/start" android:layout_weight="0.50" android:onClick="start" /> android:layout_width="0dp" android:layout_height="wrap_content" android:text="停止搜索" android:id="@+id/stop" android:layout_weight="0.50" android:onClick="stop" /> android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"> android:layout_height="wrap_content" android:id="@+id/input" android:layout_weight="0.5" /> android:layout_width="0dp" android:layout_height="wrap_content" android:onClick="send" android:text="发送命令" android:id="@+id/send" android:layout_weight="0.5" /> android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> android:layout_width="wrap_content" android:layout_height="match_parent"> android:layout_height="wrap_content" android:text="消息列表" /> android:layout_height="0dp" android:id="@+id/msglist" android:layout_weight="1" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right"> android:layout_height="wrap_content" android:text="设备列表" /> android:layout_height="0dp" android:id="@+id/devices" android:layout_weight="1" /> |
|
|
|
只有小组成员才能发言,加入小组>>
imx6ull 和 lan8742 工作起来不正常, ping 老是丢包
3414 浏览 0 评论
3384 浏览 9 评论
3073 浏览 16 评论
3561 浏览 1 评论
9212 浏览 16 评论
1322浏览 3评论
680浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
679浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2427浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1991浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-3-8 13:54 , Processed in 0.404020 second(s), Total 45, Slave 36 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191