I have written a program that constantly reads from the Bluetooth via SPP and prints the contents in the stream to a edittext box. I have the following thread:
myTimer = new Timer();
myTimer.schedule(new TimerTask(){
#Override
public void run(){
TimerMethod();
}
},0,1000);
private void TimerMethod(){this.runOnUiThread(startReading);}
private Runnable startReading = new Runnable(){
public void run(){
EditText _txtArea = (EditText) findViewById(R.id._txtArea);
try{
inStream = btSocket.getInputStream();
}catch (IOException e3) {
_txtArea.append("inStream establishment Failed!");
}
Now the msg's incoming can be of any size and I want to keep reading until there isn't anything remaining to be read. I tried an implementation where i did something like this:
byte[] msgIn = new byte[15];
inStream.read(msgIn, 0, 15);
int len = msgIn.length;
for (int i=0; i<len; i++){
out = new Character ((char) msgIn[i]).toString();
_txtArea.append(out);
But that limits the read to 15 bytes and the code doesn't seem very effecient. If anyone is wondering why i have the following line out = new Character ((char) msgIn[i]).toString(); it's because the data coming in is in ASCII i am converting it to a char. Also using this method after reading all of the contents when there is nothing else to read the program hangs. Does anyone know a way i can keep reading until all of the data has been read?
I figured it out, for those who are interested it is because the stream should be closed before a read so that inputStream.read() will be able to reach -1 after all data has been sent
Related
I realized after going through a post in the IBM developer forums that the android sdk reads bytes from the mic recording and writes them to the websocket. I am now trying to read bytes from an audio file on memory and write them to the websocket. How should I do this? So far I have:
public class AudioCaptureThread extends Thread{
private static final String TAG = "AudioCaptureThread";
private boolean mStop = false;
private boolean mStopped = false;
private int mSamplingRate = -1;
private IAudioConsumer mIAudioConsumer = null;
// the thread receives high priority because it needs to do real time audio capture
// THREAD_PRIORITY_URGENT_AUDIO = "Standard priority of the most important audio threads"
public AudioCaptureThread(int iSamplingRate, IAudioConsumer IAudioConsumer) {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
mSamplingRate = iSamplingRate;
mIAudioConsumer = IAudioConsumer;
}
// once the thread is started it runs nonstop until it is stopped from the outside
#Override
public void run() {
File path = Activity.getContext.getExternalFilesDir(null);
File file = new File (path, "whatstheweatherlike.wav");
int length = (int) file.length();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[length];
FileInputStream in = null;
try {
in = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
for (int readNum; (readNum = in.read(b)) != -1;) {
bos.write(b, 0, readNum);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] bytes = bos.toByteArray();
mIAudioConsumer.consume(bytes);
}
However, Activity.getContext is not recognized. I can convert the file to bytes in MainActivity but how do I then write it to the websocket? Am I on the right track or is this not the right way? If it is, how do I solve this problem?
Any help is appreciated!
Activity.getContext is not recognized because there's no reference to Activity, since it's just a Thread. You would have to pass in the Activity, although it would likely make more sense just to pass in the Context if you need it.
You've got the right idea that you can create a FileInputStream and use that. You might like to use our MicrophoneCaptureThread as a reference. It'd be a very similar situation, except you'd be using your FileInputStream instead of reading from the microphone. You can check it out (and an example project that uses it) here: https://github.com/watson-developer-cloud/android-sdk/blob/master/library/src/main/java/com/ibm/watson/developer_cloud/android/library/audio/MicrophoneCaptureThread.java
I'm developing an app to communicate with a PCB board via bluetooth.
I receive a string from the PCB board to my app every 50ms. This string has the next structure:
start_byte(1byte)/battery _level(1byte)/speed(1byte)/mode(1byte)
So I'll receive a string like this (I'll put it in hex):
80464B11
each 50ms.
This is the code. First this is the ConnectedThread which listens for the communication and that sends the received message to the mainActivity:
public void run() {
byte[] buffer = new byte[1024];
int readed;
while (true) {
try {
readed = inputStream.read(buffer);
if (readed > 0) {
final byte[] temp = new byte [readed];
System.arraycopy(buffer, 0, temp, 0, readed);
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
/*Sends message to UI*/
connectionListener.msgRead(temp);
}
});
}
} catch (IOException e) {
...
break;
}
}
Then in MainActivity I operate with the received string to extract from it each value.
#Override
public void msgRead(byte[] buffer) {
String income = byteArrayToHex(buffer);
...
Here the next step would be to check for the start_byte and after this, get the other values.
But here comes my doubt. This string will be received each 50ms, so I'll be receiving something like this:
80464B1180464B1180464B1180464B1180464B1180464B1180464B1180464B1180464B11...
So, what I do to check for the start_byte is this:
String start_byte = income.substring(0, 2);
And then, if that matches with the start_byte value, I extract the rest of the values:
if (start_byte.equals("80")) {
...
Is my approach correct to face this? Won't the buffer overflow? How can I correctly check for the start_byte to the get the other values?
maybe it is usefull to just use the read() function. This function is blocking until one byte has been read. So you can make something like this:
int[] yourArray = new int[4];
for(int i = 0; i < 4; i++)
{
yourArray[i] = inputStream.read();
}
so now your string is devived in 4 int's stored in a array.
maybe this helps you out in some sort of way
I have faced the problem this way. I've created a Queue in the ConnectedThread. Each time I receive a byte[] I put it into the Queue.
LinkedList<Byte> dataQueue = new LinkedList<Byte>();
int i = 0;
while (i< temp.length) {
dataQueue.add(temp[i]);
i++;
}
Then, when I want to get them I do:
byte readed_byte = dataQueue.pop();
This way I get a byte from the head of the queue each time I do pop().
The following code is taken from here
Can someone please explain in deep how this works?
What is this handler and what does it do?
How is the while condition implemented?.
How does the loop proceed?
I have very crude understanding how the code works , it would very much benefit me if you could help me out. Thank you.
{
final Handler handler = new Handler();
final byte delimiter = 10; //This is the ASCII code for a newline character
stopWorker = false;
readBufferPosition = 0;
readBuffer = new byte[1024];
workerThread = new Thread(new Runnable()
{
public void run()
{
while(!Thread.currentThread().isInterrupted() && !stopWorker)
{
try
{
int bytesAvailable = mmInputStream.available();
if(bytesAvailable > 0)
{
byte[] packetBytes = new byte[bytesAvailable];
mmInputStream.read(packetBytes);
for(int i=0;i<bytesAvailable;i++)
{
byte b = packetBytes[i];
if(b == delimiter)
{
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String data = new String(encodedBytes, "US-ASCII");
readBufferPosition = 0;
handler.post(new Runnable()
{
public void run()
{
myLabel.setText(data);
}
});
}
else
{
readBuffer[readBufferPosition++] = b;
}
}
}
}
catch (IOException ex)
{
stopWorker = true;
}
}
}
});
workerThread.start();
}
void sendData() throws IOException
{
String msg = myTextbox.getText().toString();
msg += "\n";
mmOutputStream.write(msg.getBytes());
myLabel.setText("Data Sent");
}
Be sure to know what a thread is, or I can clarify it.
The code you provide, as you should know, is defining your workerThread. All that is written in the run method will be run in another thread, once you call start() on that thread. All the the variables defined before the run method are define in the main thread. So is the Handler.
A Handler aims at linking 2 threads. You define it in one thread (here the main thread before the run method), and you use it in another thread (in the run method) to execute some action in thread where it was defined. SO in your code, you call
handler.post(new Runnable()
{
public void run()
{
myLabel.setText(data);
}
});
from the workerThread, so
myLabel.setText(data);
will be executed from the main thread (the thread where was instantiated your handler).
Why is it doing so? Because .setText() can't be called from another thread than the main thread as it is drawing something.
The while loop checks that the thread hasn't been interrupted (by Android or something else) and that your boolean stopWorker hasn't been modified, so that there was no Exception thrown while reading from your inputStream
try{}catch(){} is just a way to manage exceptions.
.available() method gives you the number of bytes you can read from the inpuStream by calling the .read() method. If there are some available bytes (so if you phone received something from the connected device), then it reads it.
To read method works this way: you pas a byte array as argument, and it will get the available bytes from the input stream and put them into the byte array.
Then it processes the bytes received...
But for me it's not an efficient solution, because the thread will loop very fast, whereas .read() is a blocking method, so all the part checking that checking that there are some bytes available is useless, and even inefficient. .read() would make the thread sleep until new bytes are available, and thus releasing resources. Maybe there is another reason why the code is doing so but I don't see it.
Hope that's clear.
I have an iRobot with a RooTooth installed, which is a bluetooth to serial converter. It is said to operate just like a serial port and data should be received as such. I have been able to use a terminal program to send serial commands directly to it over a serial cable, and it works fine.
I can also use the app I have written to send commands from my phone to my computer which is monitoring incoming bluetooth commands, and it receives them exactly as intended.
However, when I send it from my phone to the rootooth, nothing happens. Is there something wrong about how I am sending the commands? Shown below is how I do it:
This is within a handler:
case SUCCESS_CONNECT:
ConnectedThread connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
String s = "128 131";
byte[] command = s.getBytes();
connectedThread.write(command);
Toast.makeText(getApplicationContext(), s, 0).show();
s = "137 0 100 128 0";
byte[] command1 = s.getBytes();
connectedThread.write(command1);
Toast.makeText(getApplicationContext(), s, 0).show();
This is my write() function
public void write(byte[] bytes) {
Log.i(tag, "In write");
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
The issue must be formatting, no? Anybody with experience here, your help would be greatly appreciated!
Recently I have attempted this:
String [] s = new String[2];
s[0] = "128";
s[1] = "131";
for(int i = 0; i < s.length; i++){
byte[] command = s[i].getBytes();
connectedThread.write(command);
Thread.yield();
}
String [] t = new String[5];
t[0] = "137";
t[1] = "0";
t[2] = "100";
t[3] = "128";
t[4] = "0";
for(int i = 0; i < t.length; i++){
byte[] command = t[i].getBytes();
connectedThread.write(command);
Thread.yield();
}
I have also tried this recent version including a "/n" string but that has not done anything either.
For anybody else that happens to run into this problem, it turns out that a .write() from an OutputStream will take ints even though it says it will only take byte[]. Creating an array of ints for each command and sending them int by int ended up working. No need to include spaces or new lines.
I have implemented a bluetooth connection using the now-classic Google Bluetooth Chat code. However, I have a question which I just cannot seem to wrap my brain around.
The reading of the input stream goes something like this:
public void run() {
byte[] buffer = new byte[1024]; // 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);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
Now, that's fine if I was just printing out the characters I was receiving as in the original example. However, suppose I wanted to transfer an image file. I don't know the size of the file, so I cannot count the bytes received or anything like that. In my tests, I don't seem to be ever receiving a "-1" from the input stream, which appears to be the "norm" for reading from input streams. So how can I know that I have reached the end of the file that was being sent?
Thank you for your help and your time.
It seems Android bluetooth input streams never return -1.
I guess setup a simple protocol by sending file size in the first place and EOF signals at last will help.
No it does not. Android sends -1 only when the Socket is closed as far as I know. So a workaround could be to do a reconnect, but I was trying that for hours and did not get it working, since I do not understand this "special" Code here (copied from a Stackoverflow Thread) for setting up the socket:
BluetoothSocket tmp = null;
Log.d(TAG, "New Connection initialized");
Method m;
try {
m = device.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (Exception e) {
e.printStackTrace();
}
mmSocket = tmp;
This Socket only works, when my App is started for the first filetransfer. If I want to "Reconnect" with a completely new instantiated Object (and a new Socket created with that Code), the program freezes on the blocking method mmSocket.connect(). It seems like the Method never comes to an ending. This is driving me nuts...
Try
while ((bytes = mmInStream.read(buffer) != -1)
and see if that helps.
Try this:
public void run() {
byte[] buffer;
ArrayList<Integer> arr_byte = new ArrayList<Integer>();
while (true) {
try {
int data = mmInStream.read();
if(mmInStream.available()>0) {
arr_byte.add(data);
} else {
arr_byte.add(data);
buffer = new byte[arr_byte.size()];
for(int i = 0 ; i < arr_byte.size() ; i++) {
buffer[i] = arr_byte.get(i).byteValue();
}
Log.e("INPUT",new String(buffer));
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
arr_byte = new ArrayList<Integer>();
}
} catch (IOException e) {
break;
}
}
}