I am trying to increase the transfer speed on android bluetooth. I experimented transferring a 2.7MB buffer from one android device to another using RFComm socket of the Bluetooth API (see code below). It took ~70 secs to complete. I compared this method against the "Share" via bluetooth function that came with the phone. The "Share" function gave exceptionally better performance (~15 secs to transfer a 2.7MB file).
How does the "Share" function differ from using the Bluetooth API? How can I replicate the "Share" method to get optimized transfer speed?
Thanks,
Bluetooth API test code:
Server side - installed on one android device
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("DeviceName", MY_UUID);
socket = mServerSocket.accept();
mInStream = socket.getInputStream();
int totalByte = 1;
while (totalByte < 2718720)
{
int bytesAvailable = mInStream.available();
if (bytesAvailable > 0) {
totalByte += bytesAvailable;
byte[] buffer = new byte[bytesAvailable];
mInStream.read(buffer);
}
}
Client side - installed on other android device
mClientSocket = device.createInsecureRfcommSocketToServiceRecord(
MY_UUID);
mClientSocket.connect();
mOutStream = mClientSocket.getOutputStream();
byte byteValue = 0;
for (int i=0; i<2718720; i++) {
byteValue++;
mOutStream.write(byteValue);
}
Related
We are experimenting with a bunch of new tablets, and every one we tried is having issues with slow transfer rates with the RN4678 board. We currently use the Lenovo M10 FHD Plus. We tried a few such as the Teclast M40S, Nokia T20, and Samsung Galaxy Tab A8. The first two had horrible transfer rates, while the latter was okay but not ideal. We cannot use the Lenovo M10 Plus 3rd Gen because the buttons are too close to the corner to use with our tablet holders.
Here is my code:
public void SendMessage(BluetoothSocket socket, String msg) {
OutputStream outStream;
try {
outStream = BluetoothConnectionService.outputStream;
outStream.write("S".getBytes());
Thread.sleep(4000);
processThread = true;
mApp.running = true;
BluetoothSocketListener bsl = new BluetoothSocketListener(socket,
CollectingDetail.this);
Thread messageListener = new Thread(bsl);
messageListener.start();
timer = new CounterClass(remaingTime, 1000);
timer.start();
bt_stop.setText("Stop");
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(bluetoothReceiver, filter);
bluetoothReceiver.setRegistered(true);
} catch (IOException | InterruptedException e) {
Log.e("BLUETOOTH_COMMS", e.getMessage());
connectSocket();
}
}
public static class BluetoothSocketListener implements Runnable {
private final WeakReference<CollectingDetail> wrActivity;
private BluetoothSocket socket;
public BluetoothSocketListener(BluetoothSocket socket, CollectingDetail collectingDetail) {
this.socket = socket;
wrActivity = new WeakReference<CollectingDetail>(collectingDetail);
}
#Override
public void run() {
final CollectingDetail activity = wrActivity.get();
if (activity != null) {
activity.inStream = null;
if (!Thread.currentThread().isInterrupted()) {
int bufferSize = 512;
byte[] buffer = new byte[bufferSize];
Log.i("Bluetooth bytes", new String(buffer));
activity.inStream = BluetoothConnectionService.inputStream;
int availableBytes;
int bytesRead = -1;
String message = "";
while (activity.processThread) {
message = "";
try {
availableBytes = activity.inStream.available();
if (availableBytes > 0) {
bytesRead = activity.inStream.read(buffer);
if (bytesRead != -1 && bytesRead < bufferSize) {
message = new String(buffer, 0, bytesRead);
if (activity.mainHandler != null) {
activity.mainHandler.post(new MessagePoster(message, activity));
}
}
}
} catch (IOException e) {
Log.e("BLUETOOTH_COMMS", "Error reading bytes");
try {
socket.close();
} catch (IOException e1) {
Log.e("BLUETOOTH_COMMS", "Could not close socket");
}
activity.processThread = false;
}
}
}
}
}
}
public void seprateData(String message) {
try {
message = message.replaceAll("(\\r\\n|\\n|\\r)", ",");
String[] a = message.split(",");
boolean goodData = false;
for (int i = 0; i < a.length; i++) {
final String data = a[i];
if (data.length() > 0 && !data.equals(" ")) {
if (data.length() >= 10 && data.startsWith("5A")) {
al_sepratedMessageList.add(data);
goodData = true;
}
}
}
if (goodData) {
calculation();
if (ConnectThrough.equalsIgnoreCase("usb")) {
UsbConnectionSerivce.sendMessage("K");
} else {
BluetoothConnectionService.sendMessage(socket, "K");
}
}
} catch (Exception e) {
Log.e("BiSym", "Error Parsing BiSym Data");
}
}
Is there any way we can increase the transfer rate without changing the firmware? It appears others have faced similar problems, but none of the answers have a real solution. Could you please help me out. Thanks.
I fear this may not be software-solvable and may be an issue with BT hardware or firmware. How would I communicate with my boss about this?
I fear this may not be software-solvable and may be an issue with BT hardware or firmware. How would I communicate with my boss about this?
The difference is in the quality of the filtering of the signal, a better filter, narrower bandwidth, means lower Signal to Noise Ratio. Lower SNR means faster transfer.
Better analog filters, mean more components and slightly more cost and loss, however, due to the wide-band nature of Bluetooth, most analog filters can only filter out of band signals (nearby AM/FM/TV broadcasters).
In addition to the analog filters, digital filters are applied to the signal to narrow the bandwidth within the band, this technique incurs little loss, but requires more processing power to be included in the chip, more transistors, more costs.
The order of the filter and the type FIR or IIR determine the characteristics of the filer.
Most designers will minimize the cost to meet the minimum specifications, some will balance the cost versus performance and go further, you never know.
You tell your boss, the the better platforms perform digital filtering well beyond what the Bluetooth specification requires.
I just tested the Teclast M40 Plus which doesn't have this problem.
Something wants to make me believe it is an issue with the UNISOC Bluetooth stack. The Teclast M40 Plus has MediaTek which doesn't have this issue.
EDIT: Also tested on Lenovo M10 Plus 3rd Gen with MediaTek Helio G80, no issue. If we have to use it, we may need a new tablet holder.
Have you repeated the tests? Bluetooth uses the same frequencies as 2.4 GHz Wifi and microwave ovens. In a congested Wifi environment, and/or too many Bluetooth connections(mice, keyboards, headphones, speakers, watches ...), slowdowns are normal for high-speed transfers.
Wifi 6 MIMO utilizes all three distinct channels in the 2.4G band, (1,6,11) of the 12 overlapping. Higher bandwidth/speeds are available in 5.4G (and above), but wall penetration and signal propagation factors keep 2.4G as the primary band in the absence of other possibilities.
There is only so much space in the 2.4G band that Bluetooth operates.
Repeat your tests in an area without interference and see if you get the same results.
A cheap isolation method is to build a Faraday Cage out of .25 inch chicken wire fencing. Isolate the sender and receiver inside of the cage and measure the throughput.
In an uncontrolled environment, hundreds to thousands of tests for each device are required across different time spans to establish a true baseline measurement. You never know when you neighbor is going to start or stop a variable bit-rate video, or move a mouse.Every action contributes to the background noise in the band.
I have a bluetooth GPS that outputs data at around 2000bytes/sec. When I first start my app it is able to keep up with this rate, but within about 5-10 seconds the rate falls all the way down to 500bytes/sec. From there it goes up and down (between 300bytes/sec and 700bytes/sec usually, but I've seen as high as 6000bytes/sec as a quick spike when it tries to catch up). The stream just falls further and further behind and data ends up getting dropped (the GPS is outputting 10 samples per second and it gets to the point where I will miss several seconds worth of data).
When I connect to this same device via bluetooth from my laptop I get all the data no matter how long it runs. So I know the device itself is able to transmit at this rate. But on android (HTC Droid DNA) it falls behind right away. I have tried bumping up the thread priority and that didn't help. The app stays in the foreground the entire time with the screen on. I have also tried it without the phone plugged into the debugger just in case that was slowing things down and it's still the same issue. I don't know if this is a bluetooth stack speed issue, or a thread priority issue or what. Any ideas?
UPDATE: I just tested the same code on my Galaxy Tab 10.1 and it is able to maintain around 2000 bytes/sec indefinitely. I then tested on an old Motorola Photon 4G and it also is able to maintain the data rate. On the Droid DNA I tested with WiFi disabled as well to see if that was hurting bluetooth performance but it didn't make a difference. And because the DNA is able to do the higher rate for 5-6 seconds I would think the hardware has the capability. For some reason it just falls off after that...
OutputStream mmOutputStream;
InputStream mmInputStream;
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //Standard SerialPortService ID
mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
mmSocket.connect();
mmOutputStream = mmSocket.getOutputStream();
mmInputStream = mmSocket.getInputStream();
dataReader();
...
...
void dataReader()
{
worker = new Thread(new Runnable()
{
public void run()
{
int priority = Process.getThreadPriority(Process.myTid());
Log.d("testApp", String.format("data thread priority %d", priority));
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
priority = Process.getThreadPriority(Process.myTid());
Log.d("testApp", String.format("data thread priority %d", priority));
int bufferSize = 1024;
byte[] readBuffer = new byte[bufferSize];
long time1 = System.currentTimeMillis();
long time2 = 0;
long datacount = 0;
while(!Thread.currentThread().isInterrupted() && !stopWorker)
{
try
{
// read what we can
int bytesRead = mmInputStream.read(readBuffer);
datacount += bytesRead;
time2 = System.currentTimeMillis();
// every second output the data rate
if (time2 - time1 > 1000)
{
final float rate = ((float)datacount * 1000.0F) / (float)(time2 - time1);
handler.post(new Runnable() {
public void run()
{
String text = String.format("%.1f bytes/sec", rate);
myLabel.setText(text);
}
});
time1 = time2;
datacount = 0;
}
}
catch (IOException ex)
{
stopWorker = true;
}
}
}
}
}
In my application I'd like to get all the IP addresses that are taken by computers in the LAN using the broadcast address. I used the following code to determine the broadcast address.
InetAddress getBroadcastAddress()
{
try
{
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcp = wifi.getDhcpInfo();
// handle null somehow
int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
return InetAddress.getByAddress(quads);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
Now that I have it, as far as I know, when one uses the broadcast address, every computer answers it, so if I simply send a "ping" message to that address, the computers of the LAN will answer it. How should I ping them in Android? What command would send me the taken addresses?
The following code simply returns the packet from the sending phone but I need the computers' addresses:
int PORT = 8080;
int DISCOVERY_PORT = 8080;
try
{
DatagramSocket socket = new DatagramSocket(PORT);
socket.setBroadcast(true);
String data="TEST";
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
getBroadcastAddress(), DISCOVERY_PORT);
socket.send(packet);
byte[] buf = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(buf, buf.length);
Log.w(Tags.DEBUG,"Receive start");
socket.receive(packet2);
Log.w(Tags.DEBUG,packet2.getAddress().toString());
}
catch (Exception e)
{
e.printStackTrace();
}
Is it even possible?
EDIT:
If I'm honest it works as it is written: my phone sends an UDP packet and my phone receives the incoming packages. As the only package is coming from my phone, it is obvious that the address is my phone's address. However, if the broadcast address is valid, each network interface should send the signal back. Am I correct?
You are partially correct.
When you send a UDP packet to a broadcast address, all the computers on the network will receive the packet, unless a router on the network restricts UDP packets being sent to the broadcast address. This is mostly the case on a corporate network.
But not all computers will reply to that packet, they need to know what to do with it.
Either you write a server application that understands your UDP packet and is configured to reply to that packet and deploy that server application to all of the computers on the network.
Or you implement an existing discovery protocol such as Bonjour (Mac) or SSDP (Windows)
I suggest you take a look at ZeroConf Service Discovery if you want to use existing protocols rather then deploying your own application.
http://en.wikipedia.org/wiki/Zero-configuration_networking#Service_discovery
I hope this explanation helps you with your problem.
I am trying to make application for reading external storage file system connected using OTG cable to XOOM with ICS.
i am using this code to determine IN and OUT endpoint for communication with flash device
final UsbDeviceConnection connection = manager.openDevice(device);
UsbInterface inf = device.getInterface(0);
if (!connection.claimInterface(inf, true)) {
Log.v("USB", "failed to claim interface");
}
UsbEndpoint epOut = null;
UsbEndpoint epIn = null;
// look for our bulk endpoints
for (int i = 0; i < inf.getEndpointCount(); i++) {
UsbEndpoint ep = inf.getEndpoint(i);
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
epOut = ep;
} else {
epIn = ep;
}
}
}
if (epOut == null || epIn == null) {
throw new IllegalArgumentException("not all endpoints found");
}
final UsbEndpoint inEndPoint = epIn;
it works normal.
then i am trying to read first 512 bytes to get FAT32 boot sector
ByteBuffer arg1 = ByteBuffer.allocate(512);
UsbRequest request = new UsbRequest();
request.initialize(connection, inEndPoint);
request.queue(arg1, inEndPoint.getMaxPacketSize());
UsbRequest result = connection.requestWait(); // halt here
connection.releaseInterface(inf);
connection.close();
but it does not read any data from connected device.
all this code run on separate thread after granding permission on device
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(USBHostSampleActivity.this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
manager.requestPermission(lDevices.get(position),mPermissionIntent);
in Broadcast receiver i just start new thread with previous code;
i also tried to make call to
USBDeviceConnection.controlTransfer
byte[] b = new byte[0x10];
int cTransfer = connection.controlTransfer(128, 6, 16, 0,b, 12, 0);
like in libusb sample to get f0 data and/or hwstats but it always return -1
also i tried replace async request using USBRequst to sync bulkTransfers but result is the same.
Have anyone worked with this part of Android SDK?
Thanks!
It appears you are missing a whole protocol layer; you can't just read 512 bytes from the device. What should it send back? How could it know you want to start to read at the beginning of the disk?
How you actually read a memory location from USB-MSC device depends on the device sub class type and the supported transport protocol.
It is likely that an ordinary flash disk uses the SCSI transparent command set in conjunction with the USB Mass Storage Class Bulk-Only (BBB) Transport.
You have to examine the device descriptor to find out what your device supports. See also the MSC device class overview for all possible values and references to their documentation.
I wrote a library for that called libaums: https://github.com/mjdev/libaums
The library takes care of low level USB communication and implements the FAT32 file system. It also includes an example app. Listing a directory would work as follows:
UsbMassStorageDevice[] devices = UsbMassStorageDevice.getMassStorageDevices(this);
device.init();
// we only use the first device
device = devices[0];
// we always use the first partition of the device
FileSystem fs = device.getPartitions().get(0).getFileSystem();
Log.d(TAG, "Capacity: " + fs.getCapacity());
Log.d(TAG, "Occupied Space: " + fs.getOccupiedSpace());
Log.d(TAG, "Free Space: " + fs.getFreeSpace());
UsbFile root = fs.getRootDirectory();
for(UsbFile f : root.listFiles())
Log.d(TAG, f.getName())
I would like to know about the 'service discovery' mechanisms supported by android - particularly, Printer Discovery.
Does android provide such a discovery option? example : support for snmp broadcast?
I tried out an application "PrinterShare" link : http://www.printeranywhere.com/mobile.sdf where Printer Discovery is achieved through ipp.
Any help is appreciated.
Roy, I came across the same problem as you, and was even getting the same behavior when running that code snippet on an actual device (while running the code standalone, not in android, worked fine). I found this page and got it working, although only on the device, by using the following to figure out the Broadcast IP (instead of 239.255.255.250):
InetAddress getBroadcastAddress() throws IOException {
WifiManager wifi = mContext.getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcp = wifi.getDhcpInfo();
// handle null somehow
int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
return InetAddress.getByAddress(quads);
}
Hope that helps:)
Does android provide such a discovery option?
Not that I am aware of, sorry.
This code snippet works fine on J2SE. However, on the Android emulator, I get a 'Time Out Exception' with response = 'null'
`DatagramSocket clientSocket = new DatagramSocket(8888);
clientSocket.setSoTimeout(20000);
/**
* SSDP is a text-based protocol based on the Hypertext Transfer Protocol (RFC 2616).
* However, it uses the User Datagram Protocol (UDP) as underlying transport protocol.
* Services are announced by the hosting system with multicast addressing to a
* specifically designated IP multicast address at port number 1900. In IPv4,
* the multicast address is 239.255.255.250.
*/
//getByName(host) //host the hostName to be resolved to an address or null.
InetAddress group = InetAddress.getByName("239.255.255.250");
//host can be null which means that an address of the loopback interface is returned.
if(group == null){
Log.d("Discovery","getByName(): returns address of loopback interface.");
}
byte[] sendData;
byte[] receiveData = new byte[128];
String sentence = "M-SEARCH * HTTP/1.1\r\n"
+ "HOST: 239.255.255.250:1900\r\n"
+ "MAN: \"ssdp:discover\"\r\n"
+ "MX: 10\r\n"
+ "ST: ssdp:all\r\n"
+ "\r\n";
sendData = sentence.getBytes();
//public DatagramPacket (byte[] data, int length, InetAddress host, int port)
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, group, 1900);
try {
clientSocket.send(sendPacket);
} catch (Exception e) {
e.getMessage();
e.printStackTrace();
}
Log.d("Discovery","sent packet...");
while( true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
try
{
boolean isc = clientSocket.isConnected();
clientSocket.receive(receivePacket);
}
catch ( Exception Ex)
{
Log.d("Discovery","Time out Exception");
}
if (receivePacket.getAddress() == null)
{
Log.d("Discovery","receivePacket.getAddress() == null");
break;
}
Log.d("Discovery","Senders Address : " + receivePacket.getAddress().getHostAddress());
String controllerResponse = new String(receivePacket.getData());
} //end of while()
clientSocket.close(); `
For evaluation of SSDP in .NET this library may be useful
https://yortw.github.io/RSSDP/