Monthly Archives: April 2015

Data speed tests data for Bt-connector library

I have been trying to get some meaningful data for the Bluetooth connection speed, have to say that its rather hard since the connections appears to be rather unreliable, at least with KitKat versions.

In general its hard to put any exact values on how well Bluetooth connections are working, it appears to vary heavily between different tests, and in some tests nearly all connections are successfully sending data, and in other tests there are loads of connections in which the data just stops coming in from the receiver side.

While doing the test I got feeling that with my app, if the 1 Mb is not coming in 30 seconds, then it likely indicates that the socket is somehow jammed, and the full 1 Mb of the data will not arrive any reasonable time, or even it would never arrive fully, thus I set a timeout value to be 30 seconds, and if the 1 Mb data is not received during that time, then the app will disconnect the connection and mark the connection as cancelled.

Then as said, its really hard to put any exact values for how many percentages of connections would get cancelled due exceeding the timeout value. With Lollipop, in one earlier test I saw Nexus 5 with 5.1 Lollipop receiving almost 800 1 Mb messages without cancelling any, but then again sometimes I have seen the cancellation rate being around 5 % also with Lollipop.

With KitKat the cancellations are generally higher, there has been short tests where the cancellation rate has been similar to Lollipop, but in most cases cancellations are around 25 %, so that would be the value I would be expecting to see with KitKat.

Note of course that the tests were done in close proximity, thus on that point of view, the values are best case values.

For the successful connections we measured the time it took to send and receive the 1 Mb junk of data, and the following table shows how many messages were received by each test device, between each time segments.

ReceivingBt_times

Then following table shows the calculated averages for receiving for each device, as well as the average calculated form the devices values.

 

ReceivingBt_values

And the next table shows for both sending and receiving values from slightly different point of view.

ReceivingBt_summa

So the Median value for receiving 1 Mb is around 6 seconds, and the average is then around 8 seconds.

From the second table we could also see that 99% of messages were received under 20 seconds, which would indicate that we could adjust the timeout to be smaller without losing too much messages for cancellations.

Library updated

One of the tasks in my todo list was to update the released library with ways on making it easier to adapt it to different applications, thus I added 3 arguments into the constructor function.

Now along side the original Context and Callback arguments, you also need to supply Selector, settings and InstancePassword arguments.

The Selector is other callback interface, which can be set to null as well. it is set if the application wants to get knowledge on the services discovered and wants to implement selection of the device which the connection is to be made to. Basically the interface function will be called with array of discovered devices presented by ServiceItem instances, and the function must return one of the service items as selected device, to which the library will attempt open connection to.

The Settings argument will be instance of BTConnectorSettings, which with the application will tell the library the SERVICE_TYPE used with Wifi Direct services, the UUID used with Blue tooth connections as well as String to be used as a name for Blue tooth.

The InstancePassword is then used for encrypting the instance name variable used for delivering the Blue tooth address information, so it would be not directly human readable.

Each application using the library, should use own unique SERVICE_TYPE, UUID and InstancePassword to avoid any possible conflicts with other applications using the library.

I was also running some tests with the library, and found out that there is high change that two devices are trying to connect each other exactly the same time, which appears to create sockets which will cause exceptions with first read/write, even when they appears to be connected and also will report the remote device information correctly. Tests where I had 2-4 devices doing the tests, were indicating that up to 10% of concoctions did fail this way.

To fix this, the library now also implements really simple handshake, in which both ends are reading& writing few bytes, before the socket is given to the application.

Power consumption with WiFi Direct discovery

One of the big concern with the WiFi Direct API usage is that you might get your battery drained really fast. Have not seen any data on this, thus to figure out how big the problem is, we need to do some testing with it.

Also somebody suggested that Peer discovery would be consuming less power than doing full Service discovery, so we needed to check that out as well.

With the tests I was using my WifiPowerTest application, and with different tests I was simply commenting parts that were not needed out. Also some additional tests will be carries out using the same app, thus it likely will be modified to suit more testing in the future.

With first tests I was doing “normal” discovery, i.e. first doing peer discovery, and once I get Peers changed event, the logic would kick the service discovery on. Then there is timer to collect services discovered, thus each Services got event actually can have 1 to many services discovered.

First lets see how out Peers discovered, and Service discovery start events look for the test:

Peers_Service_Full

The main issue here to see is that Lollipop devices appears to be discovering both peers as well as services a lot less than the Kitkat counterparts. And as we can see from the next image, this corresponds directly to the services discovered.

ServiceGot_Battery_Full

From the image we can also see that,the less discovered peers & servies, also appears to mean less battery usage. Then lets look into the actual battery consumption be the test devices

Battery_FullDiscovery

The left part of the image shows the timings when the battery level went under the percentage value. The read values with gray background are estimates, since the test only lasted a bit less than 24 hours.

The right side of the image then shows how many hours it took to drop each 10% of the battery status. And to take out any chance than the devices were not actually 100% charged in the beginning, the values are calculated only from the 90% charge.

For the Nexus 4 device we would need to do longer tests to get more accurate values, but if we get general estimate from the values gotten we could say:

  1. With Nexus 5 device using 5.01 Lollipop we expect that doing full service discovery, the battery would drop 10% for each 5.2 hours of discovery.
  2. With Nexus 5 using 4.4.X Kitkat  we expect that doing full service discovery, the battery would drop 10% for each 2.5 hours of discovery.

And then lets see how the situation changes, if we would only do Peer discovery, and not start any service discoveries. Following image shows the Peer discovery data on top, and the data from the test done previously with Peers & service discovery in the bottom:

Battery_Peers

So we did expect to get less battery drainage, but instead we got the battery drained faster. And as we can see from the image, we also get more Peers changed events, thus it appears that doing service discovery will slow the Peer discovery down a bit, as well as it will make the discovery to consume less power.

And here’s the timings for the Peer only discovery:

Battery_PeersOnly

So we would see that now the 10% battery drop with Kitkat takes only 2.2 hours, but more interestingly, the Lollipop power savings we saw earlier are now gone, and the battery is drained with same speed also when using Lollipop.

The values shown here are estimates, the accuracy is really a question-mark, due the estimations used with Lollipop. Thus longer testing time will be needed for next test, but before we get better values, I will be researching for ways to reduce the power consumption on the discovery stage.

 

 

More Strange behavior with Wifi-Direct API

With the discovery parts of the logic, there has been suggestions to skip the Peer discovery part and go strait to the Service discovery, for example P2Feed says that “For the purposes of a peer-to-peer app, service discovery is more useful.“, while this can be completely true, its could also be source of additional problems.

The first issue which comes to my mind, is the way the the WiFi Direct API is designed, its doing the peer discovery in background in all cases, thus skipping the peer discovery does not really do any savings on the API point of view, though if it makes your logic work better, then go for it.

Second issue, which I do not fully understand, is that when doing the connect to other device, it must be on some discovery list. Supposing that it must be at least in current Peers list (since we can do connection without service discovery). Have not seen any docs for this, but stumbled upon a post at Stackoverflow. As I assumed that the Peers discovery is done automatically, this should not be any issue really, just remember not to stop any discoveries, until you are connected (or at least connecting).

Then also p2Feed use case of course is rather simple, you do quick discovery and connect, with Thali, we would need to do continuous discovery over extended periods of time, thus to be able to know whether the method would be suitable, we would need to do some testing with it.

With first test I modified the original power tests application to not make any Peer discovery request and let it run for few hours. Results for started service discovery events and actual services discovered can be seen from the image below:

ServiceOnly_strange2

Basically what you can see from there, is that we get really low number of services discovered, and on some point of time we stop discovering any services, and after that point, no services are discovered anymore. There is also a strange  increase on the rate of services discovered shown in the graphs. And the reason for this behavior is that, for some unknown reason the device starts giving higher rate of Peers changed events as can be seen from the following image:

SO_Peers_battery_strange2

So, that would indeed indicate that we might do better if we would do Peer discovery also, and not just service discovery. Thus the next trial was then starting Peer discovery each service time-out timer caused a reset (will fire if we don’t get services discovered within 10 minutes), as well as every time we get Discovery stopped event. Thus the Peer discovery should indeed be active at all times.

The service discovery behavior can be seen in following picture:

Discovery_strange2

As we can see from the graphs, the number of peer discovery requests is starting to raise as we get into the situation where we don’t get any services discovered anymore. Anyhow, the peer discovery requests alone are not fixing the issue, and the app never gets any new services discovered after it hits the problem.

Note also that all Peers discovery as well as service discovery requests were succeeding, and there were no error indications that could be used in apps logic to figure out what goes wrong.

The Peer changed events are again, received just fine:

Peers_battery_strange2

So I would summarize that, using the service discovery as only approach for finding peers does not work, if the logic needs to run over extended periods of time.

Then I wanted to see whether I could recover from the situation, and decided to try a new approach. With the latest versions of the modified power tests app, I implemented a new reset logic. Now when there has not been any services discovered in last 10 minutes the reset logic will turn the Wifi off, and once we get event that its off, it will be turned back on, and the logic for discovery is started again. With this test, the peer discovery was used same way as was with the second approach.

In general this approach appears to work really well, and it appears that we do get the service discovery going on normally by doing the reset with Wifi. the results can be seen from the image below:

WOF_Discovery_strange2

As seen from the graphs the service discovery started, generally generates nearly same amount of actual service discovery events, which is what we would want to see there indeed.

The Nexus 5 with 4.4.4 Kitkat though does stop working on one point and never recovers, but before going deeper, lets see how the battery consumption alongside the Peers changed events went:

WOF_Peers_battery_strange2

The point here is that when all goes well, we get the battery drained in 24 hours in all devices (same with Kitkat and Lollipop), exception being the Nexus 5 with 4.4.4. Kitkat, which nearly stops consuming battery as well as getting Peers changed events at the same time it stops discovering services. With other devices there were nearly no errors reported with discovery requests, but with the problematic Nexus 5 we see following:

WOF_444_Error_strange2

Basically what we see there is that all Peer requests as well as service requests are failing, and after seeing the battery status graph, I would strongly suspect that the reason for this behavior is that the WiFi Direct API service crashed, and only way to recover then would be rebooting the device.

So to summarize my findings, Firstly I would not suggest utilizing Service discovery only without using Peer discovery first.

Secondly, Turning WiFi off and then back on will help on recovering from situations where no services are discovered.

And thirdly the API is really not as stable as it should be for the workaround and using the workaround can lead into situations where device reboot is required to recover.

First library release

All though there are still plenty of work to be done, I did manage to put together first release, and with it you could have the discovery and data-channel establishment fully automated, and then have your application to implement the logic for data exchange.

Source codes for the project can be found from thaliproject/BTConApp. I’ll be updating it time to time, and likely will make other libraries as well.

This library is using mixing technologies, the reasoning was to find technologies that would enable us to get the discovery & data exchange to work without pairing, human interaction as well as with minimal interruptions to other communications happening from the device. Also we required the library to be able to work on both Lollipop & Kitkat versions of Android.

The technologies used are:

  1. Wifi-Direct for Peer & service discovery. The Bluetooth address is also delivered through the local service advertising
  2. Unsecure-Bluetooth sockets for data exchange.

The delivery also includes a sample application which is also doubling as a end-to-end test application. Basically you would open the app in two separate devices, and let it run.

While running the app, it does the following:

  1. It tries to find other instances of it running in other devices,
  2. If it finds one, it tries to make connection to it.
  3. If the connection is successful, then it sends short message to the device.
  4. After the short message is received, the device which was connected to (i.e. not the one that started the communication process) sends 1 Mb data chunk to the other device.
  5. After receiving the 1 Mb data chunk, the connection is closed, and the discovery process is started again.

With the app, there is 1 minute timer, which after it will display summary of the steps executed, and later on automated test report sending could be added in this view.

If you want to add the library in your own app, at its current stage, you would need to add it as a module to your project. Then create instance of the BTConnector class. For it you need to give the main apps Context, and a callback.

The Callback is really simply, it requires two functions to be implemented:

  • Connected(BluetoothSocket socket, boolean incoming) function will be called by the library when connection is established to remote device
  • void StateChanged(State newState) function is called by the library when internal state of the library changes. possible values are:
    • Idle: The Library is ready, but not actively doing anything. (dark Gray)
    • NotInitialized: Library has not been initialized (light Gray)
    • WaitingStateChange: Bluetooth or Wifi is disabled, thus the library is waiting for them to be enabled before doing anything. (pink)
    • FindingPeers: Library is currently discovering peers. (Cyan)
    • FindingServices: Library has detected peer devices, and is now checking whether they are advertising the service we use. (Yellow)
    • Connecting: Library has discovered a device having our service, and is attempting to establish connection to it. (Green)
    • Connected: Library has established connection. (Blue)

The (Color) marked in the end of the state values is the color used in the example application to make the apps current state more visible while playing around with the app. Following video shows simple demo on how the app can be used:

During testing we also have found out that, the Bluetooth connections can be rather unreliable when it comes to the data speed, and as the library simply gives the socket to the application handling the communications, the data channel monitoring must be handled in the application level separately.

As an example here’s video of old version of the test app

This app version only had a timeout timer for 60 seconds, and its reset only if the data channel is completely idle for full 60 seconds. This approach is bad, since there might be data coming, but its coming really slow.  With this video the normal time it takes to send/receive the 1 Mb data chunk, is bout 5-10 seconds, there are loads of times it takes more, but generally more than 90 % is handled in less than 30 seconds. The longest time to receive the 1 Mb that ended successfully can be found from 11:50, and it lasted 496 seconds.

The recommendation for approaching this issue, would be to measure bigger chunks and have timer to verify that the amount of data received is above the threshold limit. And if it is not, then disconnect the socket and start the discovery process again.

I will be writing some suggestions for the values later, after I have done some measurements on the timings in general.