I am trying to convert the speech to text in android.In my project i am having two buttons namely Record and Stop.
If i click the record button the speech will be recorded from the user, after triggering the stop button recorded speech will be saved in FLAC format and then that sound will be send to Google API for transcription[ie., speech to text]
Well it is working fine, but it is taking much more time to convert the speech to text if the speech is too large.
Can any one please tell me how to increase the speed and performance of to show the text as soon as possible?
Suggestion please.
Thanks for your precious time!..
Please find the source for reference
MainActivity.java
public class MainActivity extends Activity {
String str_RecordFailed = "RECORD_FAILED";
// Language spoken
// Obs: It requires Google codes: English(en_us), Portuguese(pt_br), Spanish
// (es_es), etc
String language = "en_us";
// Key obtained through Google Developer group
String api_key = "AIzaSyBgnC5fljMTmCFeilkgLsOKBvvnx6CBS0M";
// Name of the sound file (.flac)
String fileName = Environment.getExternalStorageDirectory() + "/recording.flac";
// URL for Google API
String root = "https://www.google.com/speech-api/full-duplex/v1/";
String dwn = "down?maxresults=1&pair=";
String API_DOWN_URL = root + dwn;
String up_p1 = "up?lang=" + language
+ "&lm=dictation&client=chromium&pair=";
String up_p2 = "&key=";
// Variables used to establish return code
private static final long MIN = 10000000;
private static final long MAX = 900000009999999L;
long PAIR;
// Constants
private int mErrorCode = -1;
private static final int DIALOG_RECORDING_ERROR = 0;
// Rate of the recorded sound file
int sampleRate;
// Recorder instance
private Recorder mRecorder;
// Output for Google answer
TextView txtView;
Button recordButton, stopButton;//, listenButton;
// Handler used for sending request to Google API
Handler handler = new Handler();
// Recording callbacks
private Handler mRecordingHandler = new Handler(new Handler.Callback() {
public boolean handleMessage(Message m) {
switch (m.what) {
case FLACRecorder.MSG_AMPLITUDES:
FLACRecorder.Amplitudes amp = (FLACRecorder.Amplitudes) m.obj;
break;
case FLACRecorder.MSG_OK:
// Ignore
break;
case Recorder.MSG_END_OF_RECORDING:
break;
default:
mRecorder.stop();
mErrorCode = m.what;
showDialog(DIALOG_RECORDING_ERROR);
break;
}
return true;
}
});
// DOWN handler
Handler messageHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1: // GET DOWNSTREAM json id="#+id/comment"
String mtxt = msg.getData().getString("text");
if (mtxt.length() > 20) {
final String f_msg = mtxt;
handler.post(new Runnable() { // This thread runs in the UI
// TREATMENT FOR GOOGLE RESPONSE
#Override
public void run() {
String msg = null;
System.out.println("===transcript "+f_msg);
try {
JSONObject jsonObject = new JSONObject(f_msg);
JSONArray array = jsonObject.getJSONArray("result");
jsonObject = array.getJSONObject(0);
JSONArray array2 =jsonObject.getJSONArray("alternative");
jsonObject = array2.getJSONObject(0);
msg = jsonObject.getString("transcript");
System.out.println("===transcript "+msg);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
txtView.setText(msg);
}
});
}
break;
case 2:
break;
}
}
}; // doDOWNSTRM Handler end
// UPSTREAM channel. its servicing a thread and should have its own handler
Handler messageHandler2 = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1: // GET DOWNSTREAM json
Log.d("ParseStarter", msg.getData().getString("post"));
break;
case 2:
Log.d("ParseStarter", msg.getData().getString("post"));
break;
}
}
}; // UPstream handler end
/**************************************************************************************************************
* Implementation
**/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtView = (TextView) this.findViewById(R.id.txtView);
recordButton = (Button) this.findViewById(R.id.record);
stopButton = (Button) this.findViewById(R.id.stop);
stopButton.setEnabled(false);
// listenButton = (Button) this.findViewById(R.id.listen);
// listenButton.setEnabled(false);
mRecorder = new Recorder(this, mRecordingHandler);
}
/***************************************************************************************************************
* Method related to recording in FLAC file
*/
/*Thread th = new Thread()
{
public void run() {
};
};*/
public void recordButton(View v) {
mRecorder.start(fileName);
txtView.setText("");
recordButton.setEnabled(false);
stopButton.setEnabled(true);
Toast.makeText(getApplicationContext(), "Recording...",Toast.LENGTH_LONG).show();
/*sampleRate = mRecorder.mFLACRecorder.getSampleRate();
getTranscription(sampleRate);
mRecorder.stop();*/
}
/***************************************************************************************************************
* Method that stops recording
*/
public void stopRecording(View v) {
Toast.makeText(getApplicationContext(), "Loading...", Toast.LENGTH_LONG).show();
sampleRate = mRecorder.mFLACRecorder.getSampleRate();
getTranscription(sampleRate);
mRecorder.stop();
stopButton.setEnabled(false);
recordButton.setEnabled(true);
}
/***************************************************************************************************************
* Method that listens to recording
*/
public void listenRecord(View v) {
Context context = this;
FLACPlayer mFlacPlayer = new FLACPlayer(context, fileName);
mFlacPlayer.start();
}
/**************************************************************************************************************
* Method related to Google Voice Recognition
**/
public void getTranscription(int sampleRate) {
File myfil = new File(fileName);
if (!myfil.canRead())
{
Log.d("ParseStarter", "FATAL no read access");
Toast.makeText(MainActivity.this, "Sorry : Unable to convert the recorded voice", Toast.LENGTH_LONG).show();
}
// first is a GET for the speech-api DOWNSTREAM
// then a future exec for the UPSTREAM / chunked encoding used so as not
// to limit
// the POST body sz
PAIR = MIN + (long) (Math.random() * ((MAX - MIN) + 1L));
// DOWN URL just like in curl full-duplex example plus the handler
downChannel(API_DOWN_URL + PAIR, messageHandler);
// UP chan, process the audio byteStream for interface to UrlConnection
// using 'chunked-encoding'
FileInputStream fis;
try {
fis = new FileInputStream(myfil);
FileChannel fc = fis.getChannel(); // Get the file's size and then
// map it into memory
int sz = (int) fc.size();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz);
byte[] data2 = new byte[bb.remaining()];
Log.d("ParseStarter", "mapfil " + sz + " " + bb.remaining());
bb.get(data2);
// conform to the interface from the curl examples on full-duplex
// calls
// see curl examples full-duplex for more on 'PAIR'. Just a globally
// uniq value typ=long->String.
// API KEY value is part of value in UP_URL_p2
upChannel(root + up_p1 + PAIR + up_p2 + api_key, messageHandler2,
data2);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void downChannel(String urlStr, final Handler messageHandler) {
final String url = urlStr;
new Thread() {
Bundle b;
public void run() {
String response = "NAO FOI";
Message msg = Message.obtain();
msg.what = 1;
// handler for DOWN channel http response stream - httpsUrlConn
// response handler should manage the connection.... ??
// assign a TIMEOUT Value that exceeds by a safe factor
// the amount of time that it will take to write the bytes
// to the UPChannel in a fashion that mimics a liveStream
// of the audio at the applicable Bitrate. BR=sampleRate * bits
// per sample
// Note that the TLS session uses
// "* SSLv3, TLS alert, Client hello (1): "
// to wake up the listener when there are additional bytes.
// The mechanics of the TLS session should be transparent. Just
// use
// httpsUrlConn and allow it enough time to do its work.
Scanner inStream = openHttpsConnection(url);
// process the stream and store it in StringBuilder
while (inStream.hasNextLine()) {
b = new Bundle();
b.putString("text", inStream.nextLine());
msg.setData(b);
messageHandler.dispatchMessage(msg);
}
}
}.start();
}
private void upChannel(String urlStr, final Handler messageHandler,
byte[] arg3) {
final String murl = urlStr;
final byte[] mdata = arg3;
Log.d("ParseStarter", "upChan " + mdata.length);
new Thread() {
public void run() {
String response = "NAO FOI";
Message msg = Message.obtain();
msg.what = 2;
Scanner inStream = openHttpsPostConnection(murl, mdata);
inStream.hasNext();
// process the stream and store it in StringBuilder
while (inStream.hasNextLine()) {
response += (inStream.nextLine());
Log.d("ParseStarter", "POST resp " + response.length());
}
Bundle b = new Bundle();
b.putString("post", response);
msg.setData(b);
// in.close(); // mind the resources
messageHandler.sendMessage(msg);
}
}.start();
}
// GET for DOWNSTREAM
private Scanner openHttpsConnection(String urlStr) {
InputStream in = null;
int resCode = -1;
Log.d("ParseStarter", "dwnURL " + urlStr);
try {
URL url = new URL(urlStr);
URLConnection urlConn = url.openConnection();
if (!(urlConn instanceof HttpsURLConnection)) {
throw new IOException("URL is not an Https URL");
}
HttpsURLConnection httpConn = (HttpsURLConnection) urlConn;
httpConn.setAllowUserInteraction(false);
// TIMEOUT is required
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
resCode = httpConn.getResponseCode();
if (resCode == HttpsURLConnection.HTTP_OK) {
return new Scanner(httpConn.getInputStream());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// GET for UPSTREAM
private Scanner openHttpsPostConnection(String urlStr, byte[] data) {
InputStream in = null;
byte[] mextrad = data;
int resCode = -1;
OutputStream out = null;
// int http_status;
try {
URL url = new URL(urlStr);
URLConnection urlConn = url.openConnection();
if (!(urlConn instanceof HttpsURLConnection)) {
throw new IOException("URL is not an Https URL");
}
HttpsURLConnection httpConn = (HttpsURLConnection) urlConn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setChunkedStreamingMode(0);
httpConn.setRequestProperty("Content-Type", "audio/x-flac; rate="
+ sampleRate);
httpConn.connect();
try {
// this opens a connection, then sends POST & headers.
out = httpConn.getOutputStream();
// Note : if the audio is more than 15 seconds
// dont write it to UrlConnInputStream all in one block as this
// sample does.
// Rather, segment the byteArray and on intermittently, sleeping
// thread
// supply bytes to the urlConn Stream at a rate that approaches
// the bitrate ( =30K per sec. in this instance ).
Log.d("ParseStarter", "IO beg on data");
out.write(mextrad); // one big block supplied instantly to the
// underlying chunker wont work for duration
// > 15 s.
Log.d("ParseStarter", "IO fin on data");
// do you need the trailer?
// NOW you can look at the status.
resCode = httpConn.getResponseCode();
Log.d("ParseStarter", "POST OK resp "
+ httpConn.getResponseMessage().getBytes().toString());
if (resCode / 100 != 2) {
Log.d("ParseStarter", "POST bad io ");
}
} catch (IOException e) {
Log.d("ParseStarter", "FATAL " + e);
}
if (resCode == HttpsURLConnection.HTTP_OK) {
Log.d("ParseStarter", "OK RESP to POST return scanner ");
return new Scanner(httpConn.getInputStream());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}}
On same concept am working and same thing is happening with me in different manner. i mean when am trying to record audio more than 40 second it is not giving me output . But below than 40 sec it gives me proper output when recording length is high it mean your FLAC file size is big thats why it takes time so as per my research i found way to reduce the size of recording file by changing frequency of recording but there is disadvantage of it when you decrease the frequency the result may vary i mean it may not be accurate as compare to high frequency recording clip
so here is my suggestion to you to increase performance (But result will may varies due to this suggestion)
go into FLACRecorder.java file and in run() method use this line
final int sample_rates[] = { 8000 };
instead of
final int sample_rates[] = { 44100, 22050, 11025, 8000 };
it means During recording your sample rate will be 8000 which is very low so your recorded file size will be low and due to this it will fastly get uploaded on google server for voice recognition and performance will get improve hope this will help you
Related
Ive been trying to setup a server using ESP8266 wifi module on a particular port. I'm done with that.
I want to receive the message from it now.
Whenever I connect using socket.connect(), I am able to detect it in the esp8266. But I cant receive any message, the server sends through the same socket.
I am trying to obtain the message using DataInputStream inside a while loop continuously in a async task.Pls let me know if my approach or code is wrong! Thanks!
This is my code:
package test.espclient;
import java.io.DataInputStream;
//import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
TextView textResponse;
EditText editTextAddress, editTextPort;
Button buttonConnect, buttonClear,buttonDiscon , buttonSendMsg;
EditText welcomeMsg;
Socket socket;
boolean socketStatus = false;
MyClientTask myClientTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextAddress = (EditText) findViewById(R.id.address);
editTextPort = (EditText) findViewById(R.id.port);
buttonConnect = (Button) findViewById(R.id.connect);
buttonClear = (Button) findViewById(R.id.clear);
buttonDiscon = (Button) findViewById(R.id.closeSocket);
buttonSendMsg = (Button) findViewById(R.id.sendMsg);
textResponse = (TextView) findViewById(R.id.response);
welcomeMsg = (EditText)findViewById(R.id.welcomemsg);
buttonConnect.setOnClickListener(buttonConnectOnClickListener);
buttonDiscon.setOnClickListener(buttonDisconnectOnCLickListener);
//buttonSendMsg.setOnClickListener(sendMessage);
buttonClear.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
textResponse.setText("");
}
});
}
OnClickListener buttonConnectOnClickListener = new OnClickListener() {
#Override
public void onClick(View arg0) {
if(socketStatus)
Toast.makeText(MainActivity.this,"Already talking to a Socket!! Disconnect and try again!", Toast.LENGTH_LONG).show();
else {
socket = null;
String address = editTextAddress.getText().toString();
int port = Integer.parseInt(editTextPort.getText().toString());
String tMsg = welcomeMsg.getText().toString();
if (address == null || port == 0)
Toast.makeText(MainActivity.this, "Please enter valid address/port", Toast.LENGTH_LONG).show();
else {
myClientTask = new MyClientTask(address,port,tMsg);
myClientTask.execute();
} //else when no active socket conn. and credentials are validated.
} //else when already active socket conn.
}
};
OnClickListener buttonDisconnectOnCLickListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (!socketStatus)
Toast.makeText(MainActivity.this, "SOCKET Already Closed!!", Toast.LENGTH_SHORT).show();
else {
try {
onDisconnect();
if(myClientTask.isCancelled()) {
socket.close();
Toast.makeText(MainActivity.this, "Socket Closed!", Toast.LENGTH_SHORT).show();
socketStatus = false;
}
else
{
Toast.makeText(MainActivity.this, "Couldn't Disconnect! Pls try again!", Toast.LENGTH_SHORT).show();
socketStatus = true;
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this,e.toString(), Toast.LENGTH_SHORT).show();
}
}
}
};
// OnClickListener sendMessage = new OnClickListener() {
// #Override
// public void onClick(View v) {
// String msg = welcomeMsg.toString();
// if(msg.equals(""))
// {
// Toast.makeText(MainActivity.this, "Message is empty!!!", Toast.LENGTH_SHORT).show();
// }
// else if(!socketStatus)
// {
// Toast.makeText(MainActivity.this, "Please Establish Socket Connection first!", Toast.LENGTH_SHORT).show();
// }
// else
// {
// MyClientTask myClientTask = new MyClientTask(editTextAddress
// .getText().toString(), Integer.parseInt(editTextPort
// .getText().toString()),
// msg);
// myClientTask.execute();
//
// }
//
// }
// };
public void onDisconnect()
{
myClientTask.cancel(true);
}
public class MyClientTask extends AsyncTask<Void, String, Void> {
String dstAddress;
int dstPort;
String response ="";
String msgToServer;
MyClientTask(String addr, int port, String msgTo) {
dstAddress = addr;
dstPort = port;
msgToServer = msgTo;
Log.w("MSG","Entering async task");
}
#Override
protected Void doInBackground(Void... arg0) {
// DataOutputStream dataOutputStream = null;
DataInputStream dataInputStream = null;
try {
socket = new Socket(dstAddress, dstPort);
socketStatus = true;
// dataOutputStream = new DataOutputStream(socket.getOutputStream());
// if(msgToServer != null){
// dataOutputStream.writeUTF(msgToServer);
// }
}
catch (UnknownHostException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
socketStatus = false;
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
}
Log.w("MSG","Inside while loop for retrieving data");
while(!isCancelled()){
try {
dataInputStream = new DataInputStream(socket.getInputStream());
response = dataInputStream.readUTF();
if(!response.isEmpty())
{
publishProgress(response);
Log.w("Data:",response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// if (dataOutputStream != null) {
// try {
// dataOutputStream.close();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
if (dataInputStream != null) {
try {
dataInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Log.w("MSG","Stopping async task");
socket.close();
socketStatus = false;
} catch (IOException e) {
e.printStackTrace();
socketStatus = true;
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
textResponse.setText(values[0]);
Toast.makeText(MainActivity.this,"Server:"+values[0],Toast.LENGTH_LONG).show();
Log.w("MSG","Updating with msg");
}
#Override
protected void onPostExecute(Void result) {
Log.w("MSG","On postExecute method..");
textResponse.setText(response);
super.onPostExecute(result);
}
}
}
UPDATE(16-12-15) I made the following changes under the doInBackground().
originally, I used DataInputStream, now I replaced it with BufferedReader.
The change was made under the while loop part for constantly checking the socket input stream. Also added the ESP8266 code for reference.
Now I able to Receive the text sent from ESP8266, but it reaches only after I send 3 or 4 messages via CIPSEND cmd. for e.g. if i send "hi", "hello" "yo", after sending the third word, I receive all the words together as "hihelloyo"
Instead of recieving each message as soon as it is sent, I receive it very late.
I am not sure what exactly is causing this problem. May be the buffer size?
How to solve this ?
MODIFIED CODE:
protected Void doInBackground(Void... arg0) {
// DataOutputStream dataOutputStream = null;
// DataInputStream dataInputStream = null;
try {
socket = new Socket(dstAddress, dstPort);
socketStatus = true;
// dataOutputStream = new DataOutputStream(socket.getOutputStream());
// if(msgToServer != null){
// dataOutputStream.writeUTF(msgToServer);
// }
}
catch (UnknownHostException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
socketStatus = false;
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
}
Log.w("MSG","Inside while loop for retrieving data");
while(!isCancelled() && socketStatus) {
try {
// dataInputStream = new DataInputStream(socket.getInputStream());
// response = dataInputStream.readUTF();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
response = br.readLine();
if (!response.isEmpty()) {
publishProgress(response);
Log.w("Data:", response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
ESP266 code
#include <AltSoftSerial.h>
AltSoftSerial ESP8266 ;//(8,9)|Rx,Tx
int LED = 13;
boolean FAIL_8266 = false;
#define BUFFER_SIZE 128
char buffer[BUFFER_SIZE];
String ssid="\"SSID\"";
String pass="\"PASSWORD\"";
void clearESP8266SerialBuffer()
{
Serial.println("= clearESP8266SerialBuffer() =");
while (ESP8266.available() > 0) {
char a = ESP8266.read();
Serial.write(a);
}
Serial.println("==============================");
}
void sendHTTPResponse(int id, String content)
{
String response;
response = "HTTP/1.1 200 OK\r\n";
response += "Content-Type: text/html; charset=UTF-8\r\n";
response += "Content-Length: ";
response += content.length();
response += "\r\n";
response +="Connection: close\r\n\r\n";
response += content;
String cmd = "AT+CIPSEND=";
cmd += id;
cmd += ",";
cmd += response.length();
Serial.println("--- AT+CIPSEND ---");
sendESP8266Cmdln(cmd, 1000);
Serial.println("--- data ---");
sendESP8266Data(response, 1000);
}
boolean waitOKfromESP8266(int timeout)
{
do{
Serial.println("wait OK...");
delay(1000);
if(ESP8266.find("OK"))
{
return true;
}
}while((timeout--)>0);
return false;
}
//Send command to ESP8266, assume OK, no error check
//wait some time and display respond
void sendESP8266Cmdln(String cmd, int waitTime)
{
ESP8266.println(cmd);
delay(waitTime);
clearESP8266SerialBuffer();
}
//Basically same as sendESP8266Cmdln()
//But call ESP8266.print() instead of call ESP8266.println()
void sendESP8266Data(String data, int waitTime)
{
ESP8266.print(data);
delay(waitTime);
clearESP8266SerialBuffer();
}
void adc()
{
int ldr;
for(int i=0;i<=3;i++)
{
ldr = analogRead(A0);
sendESP8266Cmdln("AT+CIPSEND=0,5",1000);
sendESP8266Cmdln(String(ldr),1000);
delay(1000);
}
}
void setup()
{
Serial.begin(9600);
ESP8266.begin(9600);
pinMode(LED,OUTPUT);
do{
ESP8266.println("AT+RST");
delay(1000);
if(ESP8266.find("Ready"))
{
Serial.println("Module is ready");
delay(1000);
clearESP8266SerialBuffer();
sendESP8266Cmdln("AT+CWMODE=1",1000);
//Join Wifi network
sendESP8266Cmdln("AT+CWJAP="+ssid+","+pass,6500);
//Get and display my IP
sendESP8266Cmdln("AT+CIFSR", 1000);
//Set multi connections
sendESP8266Cmdln("AT+CIPMUX=1", 1000);
//Setup web server on port 80
sendESP8266Cmdln("AT+CIPSERVER=1,3333",1000);
Serial.println("Server setup finish");
FAIL_8266 = false;
}else{
Serial.println("Module have no response.");
delay(500);
FAIL_8266 = true;
}
}while(FAIL_8266);
digitalWrite(LED, HIGH);
ESP8266.setTimeout(1000);
}
void loop() {
// listen for communication from the ESP8266 and then write it to the serial monitor
if(ESP8266.available()) // check if the esp is sending a message
{
String msg = ESP8266.readString();
if(msg.substring(0,4)=="Link")
Serial.println("Client connected!");
else if(msg.substring(0,6)=="Unlink")
Serial.println("Client Disconncected!!");
else if(msg.substring(1,5)=="+IP")
{
Serial.println("Client says: "+msg.substring(9,14));
}
else
{
// Serial.println("Calling ADC.!");
//adc();
// Serial.println("Msg:"+msg.charAt(0)+msg.charAt(1)+msg.charAt(2)+msg.charAt(3));
// Serial.println("Something recieved!: "+msg.substring(1,2));
Serial.println("MSG:"+msg);
}
}
// listen for user input and send it to the ESP8266
if ( Serial.available() ) { ESP8266.write( Serial.read() ); }
}
//Clear and display Serial Buffer for ESP8266
UPDATE(17-12-15):Added pics for reference
My arduino serial window showing the AT+CIPSEND commands.
pic of the app running on phone.
As to this comment:
... it worked! I can get the messages immediately irrespective of their lengths, after i close the connection on esp side using cipclose=0. But is this is the only way? Is it possible to make the device and the app talk? How come it is possible in the telnet application, where i can continuously send data till i close connection on one side.?
On the upper application layers data from TCPIP connection is presented as a Stream. Using this stream with well-defined application protocols like HTTP or telnet, message exchange is defined. In your case basically Android side does not know what amount of data to receive. After using buffered reader you get buffered answer, not the whole.
In telnet protocol for example there are control commands. Thus the system goes on working.
To solve your case:
Close connection after every message. (this slows down things)
Implement a basic application protocol. For example: Implement a Message frame:
FRAME
1st byte : length ( this byte gives the length of the payload )
2nd...255th byte : payload ( this is the actual message )
LOGIC
-Sender packs the frame giving length and payload.
-Sender sends the data
...
-Receiver queries for the available bytes.
-When available bytes are >1 receive only 1 byte say it is 'n'
-'n' is the length of the total frame
-Read 'n' bytes from the stream. if EOF then return what is received.
In addition to this you can implement control commands.
For example you may want the receiver to close the connection so your frame can be:
Byte 1 : length
Byte 2 : command (0=nothing, 1=close conn)
Byte 3..n : payload
LOGIC
-When receiver finished receiving and command is 1 then closes the connection.
I went to a struggle. There are so many tutorials regarding this topic, but I cannot adapt any of those to my project.
What I want to do is simple:
User press the button in Android (Dialog opens, user enters numbeers, presses ok)
Arduino compares data and if it matches send one message to Android, if no - another.
Concept is this.
What I have so far is simple Arduino code
void loop() {
if (Serial.available() > 0) { // if the data came
incomingByte = Serial.read(); // read byte
if(incomingByte == '0') {
digitalWrite(LED, LOW); // if 1, switch LED Off
Serial.println("LED OFF. Press 1 to LED ON!"); // print message
}
if(incomingByte == '1') {
digitalWrite(LED, HIGH); // if 0, switch LED on
Serial.println("LED ON. Press 0 to LED OFF!");
bluetoothSerial.write
}
}
I found great tutorial for sending data from Arduino to Android, but it's made in Thread mode and I cannot adopt it to my AsyncThread solution. This is the main problem :\
My Android AsyncThread code looks like that:
private class ConnectBT extends AsyncTask<Void, Void, Void> // UI thread
{
private boolean ConnectSuccess = true; //if it's here, it's almost connected
#Override
protected void onPreExecute()
{
progress = ProgressDialog.show(ConnectedActivity.this, "Connecting...", "Please wait!!!"); //show a progress dialog
}
#Override
protected Void doInBackground(Void... devices) //while the progress dialog is shown, the connection is done in background
{
try
{
if (btSocket == null || !isBtConnected)
{
myBluetooth = BluetoothAdapter.getDefaultAdapter();//get the mobile bluetooth device
BluetoothDevice dispositivo = myBluetooth.getRemoteDevice(address);//connects to the device's address and checks if it's available
btSocket = dispositivo.createInsecureRfcommSocketToServiceRecord(myUUID);//create a RFCOMM (SPP) connection
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
btSocket.connect();//start connection
}
}
catch (IOException e)
{
ConnectSuccess = false;//if the try failed, you can check the exception here
}
return null;
}
#Override
protected void onPostExecute(Void result) //after the doInBackground, it checks if everything went fine
{
super.onPostExecute(result);
if (!ConnectSuccess)
{
Toast.makeText(ConnectedActivity.this, "Connection Failed. Is it a SPP Bluetooth? Try again.", Toast.LENGTH_SHORT).show();
finish();
}
else
{
Toast.makeText(ConnectedActivity.this, "Succeed.", Toast.LENGTH_SHORT).show();
isBtConnected = true;
}
progress.dismiss();
}
}
Solution from the tutorial:
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE: // if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
txtArduino.setText("Data from Arduino: " + sbprint); // update TextView
btnOff.setEnabled(true);
btnOn.setEnabled(true);
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
Log.d(TAG, "...Data to send: " + message + "...");
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
Log.d(TAG, "...Error data send: " + e.getMessage() + "...");
}
}
}
Full tutorial can be found here:
http://solderer.tv/data-transfer-between-android-and-arduino-via-bluetooth/
I can send data from Android to Arduino with no problem. But receiving it.. nope. Any suggestions?
EDITv2
Silly me. I've put handler and thread's code in my activity. And ran
mConnectedThread = new ConnectedThread();
mConnectedThread.start();
in AsyncTask background task. I can see valid toast message now.
Tnx!
I'm developing an app that allows to users to upload mediafiles(such as images, photos, videos) to server and I've got a little bit problem with large files - is too long to wait and view a progress bar in activity while its uploading and another problem - if app dies upload dies too so I need to transfer my uploading code to service. So here my troubles begins - if I'll transfer my upload code to server how can I send progress updates(%) to activity?
here's my upload method's code:
public static void uploadMovie(final HashMap<String, String> dataSource, final OnResponseListener finishedListener, final ProgressListener progressListener) {
if (finishedListener != null) {
new Thread(new Runnable() {
public void run() {
try {
//Prepare data-->
String boundary = getMD5(dataSource.size() + String.valueOf(System.currentTimeMillis()));
MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.setCharset(Charset.forName("UTF-8"));
for (String key : dataSource.keySet()) {
if (key.equals(MoviesFragmentAdd.USERFILE)) {
FileBody userFile = new FileBody(new File(dataSource.get(key)));
multipartEntity.addPart(key, userFile);
continue;
}
multipartEntity.addPart(key, new StringBody(dataSource.get(key), ContentType.APPLICATION_JSON));
}
HttpEntity entity = multipartEntity.build();
//<--
//Prepare Connection-->
trustAllHosts();
HttpsURLConnection conn = (HttpsURLConnection) new URL(SAKH_URL_API + "/video/addForm/").openConnection();
conn.setUseCaches(false);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("Content-length", entity.getContentLength() + "");
conn.setRequestProperty(entity.getContentType().getName(), entity.getContentType().getValue());
conn.connect();
//<--
// Upload-->
OutputStream os = conn.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
entity.writeTo(baos);
baos.close();
byte[] payload = baos.toByteArray();
baos = null;
int totalSize = payload.length;
int bytesTransferred = 0;
int chunkSize = 2000;
while (bytesTransferred < totalSize) {
int nextChunkSize = totalSize - bytesTransferred;
if (nextChunkSize > chunkSize) {
nextChunkSize = chunkSize;
}
os.write(payload, bytesTransferred, nextChunkSize);
bytesTransferred += nextChunkSize;
//Progress update-->
if (progressListener != null) {
progressListener.onProgressUpdate((100 * bytesTransferred / totalSize));
}
//<--
}
os.flush();
//<--
//Get server response-->
int status = conn.getResponseCode();
if (conn.getResponseCode() == HttpsURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
JsonObject request = (JsonObject) gparser.parse(in.readLine());
if (!request.get("error").getAsBoolean()) {
finishedListener.onLoadFinished(new Object());
}
} else {
throw new IOException("Server returned non-OK status: " + status);
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
finishedListener.onNotConnected();
}
}
}).start();
}
}
1-Create a bindable service and implement the necessary Binder
Start your service BEFORE binding to it or in other case if your app is closed the service will also close
2-Expose a public function like StartDownload(url, IUpdateTarget) on your service.
3-Create an interface (IUpdateTarget) with a function like UpdateProgress(somevalues);
4-Implement the IUpdateTarget interface in the View which should receive the update notifications
5-Bind to the service and retrieve the running service's instance
6-Now you have the instance of your service, call to StartDownload passing the URL and the target view for notifications.
7-Whenever you must update the interface from the service call to UpdateProgress from the IUpdateProgress instance passed to the service (the target view).
Beware with cross-threading calls, remember that you must always update interface on main thread.
Use Handler to send process
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
android.os.Message msg = new android.os.Message();
Bundle bundle = new Bundle();
bundle.putInt("process", process);
msg.setData(bundle);
mHandler.sendMessage(msg);
}
}).start();
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
int process = msg.getData().getInt("process");
};
};
i want to develop a app that enables two Android phones to exchange data over the Wifi Network. Since im not having two phones at the moment i thought i can try this by using 1 App that acts as a Server and another App that connects to 172.0.0.1 as a Client.
In the Server-App i start a Service that runs a NanoHTTPD Server. As a test i want to Recieve "Hallo Client" when i ask for http://172.0.0.1:8080/hallo/ . This works with the normal Android Browser.
This is what the Server looks like:
#Override
public Response serve(String uri, String method, Properties header, Properties parms, Properties files)
{
Log.d("HServer", "httpd request >>" + method + " '" + uri + "' " + " " + parms);
if (uri.startsWith("/hallo/"))
{
return new Response(HTTP_OK, MIME_PLAINTEXT, "Hallo Client");
}
else
{
return new Response(HTTP_OK, MIME_PLAINTEXT, "");
}
}
Then i made a second App with a simple test with an HttpURLConnection after the Google Example:
private String NetworkResponse;
private Runnable Erg = new Runnable()
{
#Override
public void run()
{
// TODO Auto-generated method stub
TV1.setText(NetworkResponse);
Log.d("bla", NetworkResponse);
}
};
public void Request(View view)
{
mHandler = new Handler();
Thread T = new Thread(new Runnable()
{
#Override
public void run()
{
HttpURLConnection urlConnection = null;
try
{
URL url = new URL("http://172.0.0.1:8080/hallo/");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000);
urlConnection.setConnectTimeout(10000);
BufferedInputStream in = new BufferedInputStream(urlConnection.getInputStream());
NetworkResponse = readIt(in,1000);
mHandler.post(Erg);
}
catch (MalformedURLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
urlConnection.disconnect();
}
}
});
T.start();
}
private String readIt(BufferedInputStream stream, int len) throws IOException, UnsupportedEncodingException
{
Reader reader = null;
reader = new InputStreamReader(stream, "UTF-8");
char[] buffer = new char[len];
reader.read(buffer);
return new String(buffer);
}
}
This Code works when the URL is something like http://en.wikipedia.org but not with http://172.0.0.1:8080/hallo/ . I get
07-12 01:20:00.398: W/System.err(17234): java.net.SocketTimeoutException: failed to connect to /172.0.0.1 (port 8080) after 10000ms.
So my question is: why does the Android Browser recieve an answer from my simple Server and my own App does not? Is something wrong with the way im using the HttpURLConnection?
(P.S: Im not using the Emulator, everyting is on a real Phone, both Apps have all the Permissions)
You may want to try 127.0.0.1 instead of 172.0.0.1.
I have the following web server class found here. I need to write an Android application(client) which can retrieve a file from this server. It would be great if anyone would be able to help me to do it. Thank you.
Server host address is: My-PC/ipaddress
When I execute the client it gives an exception.
java.net.ConnectException: Connection refused: connect
WebServer.Java
import java.io.*;
import java.net.*;
public class WebServer extends Thread {
public WebServer() {
this.start();
}
private void displayString(String string) { //an alias to avoid typing so much!
System.out.println(string);
}
private static final int UMBRA_PORT = 30480;
private static final int ROOM_THROTTLE = 200;
private InetAddress hostAddress;
//this is a overridden method from the Thread class we extended from
public void run() {
//we are now inside our own thread separated from the gui.
ServerSocket serversocket = null;
//To easily pick up lots of girls, change this to your name!!!
displayString("The simple httpserver v. 0000000000\nCoded by Jon Berg" +
"<jon.berg[on server]turtlemeat.com>\n\n");
//Pay attention, this is where things starts to cook!
try {
//print/send message to the guiwindow
displayString("Trying to bind to localhost on port " + Integer.toString(UMBRA_PORT) + "...");
//make a ServerSocket and bind it to given port,
//serversocket = new ServerSocket(port);
}
catch (Exception e) { //catch any errors and print errors to gui
displayString("\nFatal Error:" + e.getMessage());
return;
}
// Attempt to get the host address
try
{
hostAddress = InetAddress.getLocalHost();
}
catch(UnknownHostException e)
{
System.out.println("Could not get the host address.");
return;
}
// Announce the host address
System.out.println("Server host address is: "+hostAddress);
// Attempt to create server socket
try
{
serversocket = new ServerSocket(UMBRA_PORT,0,hostAddress);
}
catch(IOException e)
{
System.out.println("Could not open server socket.");
return;
}
// Announce the socket creation
System.out.println("Socket "+serversocket+" created.");
displayString("OK!\n");
//go in a infinite loop, wait for connections, process request, send response
while (true) {
displayString("\nReady, Waiting for requests...\n");
try {
//this call waits/blocks until someone connects to the port we
//are listening to
Socket connectionsocket = serversocket.accept();
//figure out what ipaddress the client commes from, just for show!
InetAddress client = connectionsocket.getInetAddress();
//and print it to gui
displayString(client.getHostName() + " connected to server.\n");
//Read the http request from the client from the socket interface
//into a buffer.
BufferedReader input =
new BufferedReader(new InputStreamReader(connectionsocket.
getInputStream()));
//Prepare a outputstream from us to the client,
//this will be used sending back our response
//(header + requested file) to the client.
DataOutputStream output =
new DataOutputStream(connectionsocket.getOutputStream());
//as the name suggest this method handles the http request, see further down.
//abstraction rules
http_handler(input, output);
}
catch (Exception e) { //catch any errors, and print them
displayString("\nError:" + e.getMessage());
}
} //go back in loop, wait for next request
}
//our implementation of the hypertext transfer protocol
//its very basic and stripped down
private void http_handler(BufferedReader input, DataOutputStream output) {
int method = 0; //1 get, 2 head, 0 not supported
String http = new String(); //a bunch of strings to hold
String path = new String(); //the various things, what http v, what path,
String file = new String(); //what file
String user_agent = new String(); //what user_agent
try {
//This is the two types of request we can handle
//GET /index.html HTTP/1.0
//HEAD /index.html HTTP/1.0
String tmp = input.readLine(); //read from the stream
String tmp2 = new String(tmp);
tmp.toUpperCase(); //convert it to uppercase
if (tmp.startsWith("GET")) { //compare it is it GET
method = 1;
} //if we set it to method 1
if (tmp.startsWith("HEAD")) { //same here is it HEAD
method = 2;
} //set method to 2
if (method == 0) { // not supported
try {
output.writeBytes(construct_http_header(501, 0));
output.close();
return;
}
catch (Exception e3) { //if some error happened catch it
displayString("error:" + e3.getMessage());
} //and display error
}
//}
//tmp contains "GET /index.html HTTP/1.0 ......."
//find first space
//find next space
//copy whats between minus slash, then you get "index.html"
//it's a bit of dirty code, but bear with me...
int start = 0;
int end = 0;
for (int a = 0; a < tmp2.length(); a++) {
if (tmp2.charAt(a) == ' ' && start != 0) {
end = a;
break;
}
if (tmp2.charAt(a) == ' ' && start == 0) {
start = a;
}
}
path = tmp2.substring(start + 2, end); //fill in the path
}
catch (Exception e) {
displayString("errorr" + e.getMessage());
} //catch any exception
//path do now have the filename to what to the file it wants to open
displayString("\nClient requested:" + new File(path).getAbsolutePath() + "\n");
FileInputStream requestedfile = null;
try {
//try to open the file,
requestedfile = new FileInputStream(path);
}
catch (Exception e) {
try {
//if you could not open the file send a 404
output.writeBytes(construct_http_header(404, 0));
//close the stream
output.close();
}
catch (Exception e2) {}
displayString("error" + e.getMessage());
} //print error to gui
//happy day scenario
try {
int type_is = 0;
//find out what the filename ends with,
//so you can construct a the right content type
if (path.endsWith(".zip") ) {
type_is = 3;
}
if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
type_is = 1;
}
if (path.endsWith(".gif")) {
type_is = 2;
}
if (path.endsWith(".ico")) {
type_is = 4;
}
if (path.endsWith(".xml")) {
type_is = 5;
}
//write out the header, 200 ->everything is ok we are all happy.
output.writeBytes(construct_http_header(200, 5));
//if it was a HEAD request, we don't print any BODY
if (method == 1) { //1 is GET 2 is head and skips the body
byte [] buffer = new byte[1024];
while (true) {
//read the file from filestream, and print out through the
//client-outputstream on a byte per byte base.
int b = requestedfile.read(buffer, 0,1024);
if (b == -1) {
break; //end of file
}
output.write(buffer,0,b);
}
//clean up the files, close open handles
}
output.close();
requestedfile.close();
}
catch (Exception e) {}
}
//this method makes the HTTP header for the response
//the headers job is to tell the browser the result of the request
//among if it was successful or not.
private String construct_http_header(int return_code, int file_type) {
String s = "HTTP/1.0 ";
//you probably have seen these if you have been surfing the web a while
switch (return_code) {
case 200:
s = s + "200 OK";
break;
case 400:
s = s + "400 Bad Request";
break;
case 403:
s = s + "403 Forbidden";
break;
case 404:
s = s + "404 Not Found";
break;
case 500:
s = s + "500 Internal Server Error";
break;
case 501:
s = s + "501 Not Implemented";
break;
}
s = s + "\r\n"; //other header fields,
s = s + "Connection: close\r\n"; //we can't handle persistent connections
s = s + "Server: SimpleHTTPtutorial v0\r\n"; //server name
switch (file_type) {
//plenty of types for you to fill in
case 0:
break;
case 1:
s = s + "Content-Type: image/jpeg\r\n";
break;
case 2:
s = s + "Content-Type: image/gif\r\n";
break;
case 3:
s = s + "Content-Type: application/x-zip-compressed\r\n";
break;
case 4:
s = s + "Content-Type: image/x-icon\r\n";
case 5:
s = s + "Content-Type: text/xml\r\n";
break;
default:
s = s + "Content-Type: text/html\r\n";
break;
}
////so on and so on......
s = s + "\r\n"; //this marks the end of the httpheader
//and the start of the body
//ok return our newly created header!
return s;
}
}
Client.Java
public class WatchMeManagerClient {
private static Socket socket;
private static PrintWriter printWriter;
public static void main(String[] args) throws Exception {
try {
URL url;
URLConnection urlConn;
DataInputStream dis;
url = new URL("http://ipaddress/xml/userGroup.xml");
urlConn = url.openConnection();
urlConn.setDoInput(true);
urlConn.setUseCaches(false);
dis = new DataInputStream(urlConn.getInputStream());
String s;
while ((s = dis.readLine()) != null) {
System.out.println(s);
}
dis.close();
}
catch (MalformedURLException mue) {
System.out.println(mue.toString());
} catch (IOException ioe) {
System.out.println(ioe.toString());
}
}
}
When I run the code on PC it works. But when I try to execute it on the Android Device it gives following errors.
Such problems are either due to one of the following:
The port is wrong
Firewall is stopping it.
Using Sockets require the following permission which I think you are missing:
<uses-permission android:name="android.permission.INTERNET" />
Did you allow internet access in your manifest?
<uses-permission android:name="android.permission.INTERNET"/>