简体   繁体   English

Android 语音识别并通过蓝牙将数据发送到 Arduino。 如何多次发送数据?

[英]Android voice recognition and send data via bluetooth to Arduino. How can I send data several times?

I am a newbie of Android.我是安卓新手。 My application uses Voice Recognition , TextToSpeech and send data out via Bluetooth from Android phone (SAMSUNG Galaxy Note | OS: Android 4.1.2) to Arduino.我的应用程序使用语音识别TextToSpeech并通过蓝牙将数据从 Android 手机(SAMSUNG Galaxy Note | OS:Android 4.1.2)发送到 Arduino。 It can send data out only once a time and after it can't send (it through IOException ), so application finish() .它一次只能发送一次数据,并且在不能发送之后(通过IOException ),因此应用程序finish() Below is my code.下面是我的代码。

Android Code安卓代码

package com.itcdroid.smarthome;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Locale;
import java.util.UUID;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements
    TextToSpeech.OnInitListener {

    //Tag for logging
    private static final String TAG = "ITCDroid";

    private static final int REQUEST_ENABLE_BT = 1;
    private BluetoothAdapter mBluetoothAdapter = null;
    private BluetoothSocket mBluetoothSocket = null;
    private OutputStream outStream = null;

    //MAC address of remote Bluetooth device
    private final String address = "98:D3:31:B4:34:EE";

    // UUID that specifies a protocol for generic bluetooth serial communication
    //Well known SPP UUID
    private static final UUID MY_UUID = 
            UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    private TextToSpeech tts;
    private String ttsText;
    private TextView txtSpeechInput;
    private ImageButton btnSpeak;
    private final int REQ_CODE_SPEECH_INPUT = 100;

    // Available commands
    private static final String[] commands = {"on", "off", "turn on the light", "turn off the light"};
    boolean foundCommand;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        checkBtState();

        tts = new TextToSpeech(this, this);
        txtSpeechInput = (TextView) findViewById(R.id.txtSpeechInput);
        btnSpeak = (ImageButton) findViewById(R.id.btnSpeak);

        // hide the action bar
        //getActionBar().hide();

        //mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        //checkBtState();

        btnSpeak.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                promptSpeechInput();
            }
        });

    }

    @Override
    public void onResume() {
        super.onResume();

        Log.d(TAG, "...In onResume - Attempting client connect...");

        //Set up a pointer to the remote node using it's address.
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

        // Two things are needed to make a connection:
        // A MAC address, which we got above.
        // A Service ID or UUID. in this case we are using the UUID for SPP
        try {
            mBluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
        }

        // Discovery is resource intensive. Make sure it isn't going on
        // when you attempt to connect and pass your message.
        mBluetoothAdapter.cancelDiscovery();

        // Establish the connection. This will block until is connects.
        Log.d(TAG, "...Connecting to Remote...");
        try {
            mBluetoothSocket.connect();
            Log.d(TAG, "...Connection established and data link opened...");
        } catch(IOException e) {
            try {
                mBluetoothSocket.close();
            } catch (IOException e2) {
                errorExit("Fatal Error", "In onResume() and unable to close socket during connection failture" + e2.getMessage() + ".");
            }
        }

        //Create a data stream so we can talk to server.
        Log.d(TAG, "...Creating Socket...");

        try {
            outStream = mBluetoothSocket.getOutputStream();
        } catch (IOException e) {
            errorExit("Fatal Error", "In onResume() and output stream creation failture: " + e.getMessage() + ".");
        }
    }

    @Override
    public void onPause(){
        super.onPause();
        Log.d(TAG, "...In onPause()...");

        if (outStream != null) {
            try {
                outStream.flush();
            } catch (IOException e) {
                errorExit("Fatal Error", "In onPause() and failed to flush output stream: " + e.getMessage() + ".");
            }
        }
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mBluetoothSocket.close();
        } catch (IOException e) { }
    }

    private void checkBtState() {
        // TODO Auto-generated method stub
        //Check for Bluetooth support and then check to make sure it is turned on
        if (mBluetoothAdapter == null) {
            errorExit("Fatal Error", "Bluetooth Not supported. Aborting.");
        } else {
            if (mBluetoothAdapter.isEnabled()) {
                Log.d(TAG, "...Bluetooth is enabled...");
            } else {
                //Prompt user to turn on Bluetooth
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
            }
        }

    }

    /**
     * Showing google speech input dialog
     * */
    private void promptSpeechInput() {
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
                getString(R.string.speech_prompt));
        try {
            startActivityForResult(intent, REQ_CODE_SPEECH_INPUT);
        } catch (ActivityNotFoundException a) {
            Toast.makeText(getApplicationContext(),
                    getString(R.string.speech_not_supported),
                    Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * Receiving speech input
     * */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
        case REQ_CODE_SPEECH_INPUT: {
            if (resultCode == RESULT_OK && null != data) {

                ArrayList<String> result = data
                        .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);

                foundCommand = false;
                for(String command : commands) {
                    if(result.contains(command)) {
                        foundCommand = true;
                        if(command == "on") {
                            txtSpeechInput.setText("You say -on-");
                            ttsText = "The light is turn on now.";
                            speakOut();
                            sentData("1");
                        }
                        else if(command == "off") {
                            txtSpeechInput.setText("You say -off-");
                            ttsText = "The light is turn off now.";
                            speakOut();
                            sentData("2");
                        }
                        else if(command == "turn on the light") {
                            txtSpeechInput.setText("You say -turn on the light-");
                            ttsText = "The light is turn on now.";
                            speakOut();
                            sentData("1");
                        }
                        else if(command == "turn off the light") {
                            txtSpeechInput.setText("You say -turn off the light-");
                            ttsText = "The light is turn off now.";
                            speakOut();
                            sentData("2");
                        }
                    }
                }

                if (!foundCommand) {
                    txtSpeechInput.setText("Unknown what you say");
                    ttsText = "I don't know what you want!";
                    speakOut();
                }
                //txtSpeechInput.setText(result.get(0));
            }
            break;
        }

        }
    }

    @Override
    public void onDestroy() {
        // Don't forget to shutdown!
        if (tts != null) {
            tts.stop();
            tts.shutdown();
        }
        super.onDestroy();
    }

    @Override
    public void onInit(int status) {
        // TODO Auto-generated method stub

        if (status == TextToSpeech.SUCCESS) {

            int result = tts.setLanguage(Locale.US);

            // tts.setPitch(5); // set pitch level

            // tts.setSpeechRate(2); // set speech speed rate

            if (result == TextToSpeech.LANG_MISSING_DATA
                    || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Log.e("TTS", "Language is not supported");
            } else {
                //btnSpeak.setEnabled(true);
                speakOut();
            }

        } else {
            Log.e("TTS", "Initilization Failed");
        }

    }

    //@SuppressWarnings("deprecation")
    private void speakOut() {

        String text = ttsText;

        tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
    }

    private void sentData(String message) {
        // TODO Auto-generated method stub
        byte[] msgBuffer = message.getBytes();

        Log.d(TAG, "...Sending data: " + message + "...");
        try {
            outStream.write(msgBuffer);
            outStream.close();
            reConnectBT();
        } catch (IOException e) {
            String msg = "In onResume() and an exception occurred during write:" + e.getMessage();
            msg = msg + ".\n\nCheck that the SPP UUID: " + MY_UUID.toString() + "exists on server.\n\n";

            errorExit("sentData IOException", msg);
        }

    }

    private void reConnectBT() {
        // TODO Auto-generated method stub
        Log.d(TAG, "...In reConnectBT - Attempting client connect...");

        //Set up a pointer to the remote node using it's address.
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

        // Two things are needed to make a connection:
        // A MAC address, which we got above.
        // A Service ID or UUID. in this case we are using the UUID for SPP
        try {
            mBluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
        }

        // Discovery is resource intensive. Make sure it isn't going on
        // when you attempt to connect and pass your message.
        mBluetoothAdapter.cancelDiscovery();

        // Establish the connection. This will block until is connects.
        Log.d(TAG, "...Connecting to Remote...");
        try {
            mBluetoothSocket.connect();
            Log.d(TAG, "...Connection established and data link opened...");
        } catch(IOException e) {
            try {
                mBluetoothSocket.close();
            } catch (IOException e2) {
                errorExit("Fatal Error", "In onResume() and unable to close socket during connection failture" + e2.getMessage() + ".");
            }
        }

        //Create a data stream so we can talk to server.
        Log.d(TAG, "...Creating Socket...");

        try {
            outStream = mBluetoothSocket.getOutputStream();
        } catch (IOException e) {
            errorExit("Fatal Error", "In onResume() and output stream creation failture: " + e.getMessage() + ".");
        }

    }

    private void errorExit(String title, String message) {
        // TODO Auto-generated method stub
        Toast msg= Toast.makeText(getBaseContext(),
                title, Toast.LENGTH_SHORT);
        msg.show();
        finish();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

It seems that you're doing a lot of juggling with connecting and disconnecting from your bluetooth device, which can harm your performance.似乎您在连接和断开蓝牙设备方面做了很多处理,这可能会损害您的性能。 Another thing you're doing is managing all of the heavy Bluetooth processes directly in your UI thread, which will make your app lock up until the connections complete.您正在做的另一件事是直接在您的 UI 线程中管理所有繁重的蓝牙进程,这将使您的应用程序锁定,直到连接完成。

Here's a link to my project's repository, I'm doing simple Bluetooth connections in it and made a BluetoothConnection class as a wrapper for managing the connection state. 这是我的项目存储库的链接,我正在其中进行简单的蓝牙连接,并创建了一个BluetoothConnection类作为管理连接状态的包装器。 Feel free to use the source code, but be wary that I'm always actively changing it.随意使用源代码,但请注意我总是在积极更改它。 If you choose to use it your code, the implementation would go something like this:如果你选择在你的代码中使用它,实现将是这样的:

InputStream mInputStream;
OutputStream mOutputStream;

BluetoothConnection mConnection = new BluetoothConnection("Connection Name", "98:D3:31:B4:34:EE");
mConnection.setOnConnectStatusChangedListener(this, new onConnectStatusChangedListener() {
  @Override
  public void onConnect() {
    /*
     * Connecting to bluetooth takes some time, it won't be ready immediately.
     * Set some actions here that let your program know that the connection
     * finished successfully. For example,
     */
    mInputStream = mConnection.getInputStream();
    mOutputStream = mConnection.getOutputStream();

    //Use some method of your own to write data
    sendDataToBluetoothDevice(mOutputStream);
  }

  @Override
  public void onDisconnect() {
    /*
     * Same thing applies to disconnecting, set some actions to occur
     * when the disconnect is confirmed.
     */
  }
}

/* 
 * Internally, this launches an AsyncTask to handle connecting,
 * which is why we need the onConnectStatusChangedListener
 * callbacks.
 */
mConnection.connect();

//To disconnect:
mConnection.disconnect();

This should simplify things for you by handling all of the heavy lifting in background processes.通过处理后台进程中的所有繁重工作,这应该为您简化事情。 As far as reading and writing more than once, as long as you use the InputStream and OutputStream correctly you should be golden.就多次读写而言,只要您正确使用 InputStream 和 OutputStream,您就应该是黄金。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM