Measuring Download Speed with Java/Android
Asked Answered
P

3

10

I am working on an Android app where I need to, as accurately as possible, measure the download speed of the current connection. Here's the best method I could find so far (basically I start a timer, start downloading a Linux distro from a fast server, download around 200 kbytes, then stop the timer and check time elapsed and total bytes downloaded):

try{                
    InputStream is = new URL("http://www.domain.com/ubuntu-linux.iso").openStream();
    byte[] buf = new byte[1024];
    int n = 0;              
    startBytes = TrafficStats.getTotalRxBytes(); /*gets total bytes received so far*/
    startTime = System.nanoTime();
    while(n<200){
        is.read(buf);
        n++;                
    }
    endTime = System.nanoTime();
    endBytes = TrafficStats.getTotalRxBytes(); /*gets total bytes received so far*/
    totalTime = endTime - startTime;
    totalBytes = endBytes - startBytes;
}
catch(Exception e){
    e.printStackTrace();
}   

After that I just need to divide the number of bytes transferred by the time taken and it will give the download speed in bps.

Questions: 1. Will this method be accurate? 2. Do you know a better one?

Thanks a lot.

Ponder answered 3/9, 2012 at 18:34 Comment(4)
They way you have it set up right now, it is not going to be accurate. InputStream.read is not guaranteed to completely fill your buffer. You need to check the return value to see how many bytes were actually read.Bullet
@Jeffrey, you didn't read the code in detail. I am not relying on read() to get the number of bytes. I am getting it directly from the OS via the getTotalRxBytes() function.Ponder
Ahh, my bad. I did indeed skim over that part. The solution you have will be more or less accurate.Bullet
@Jeffrey, Thanks. If you have any ideas on how to make it more do let me know.Ponder
F
6

There are a few possible problems here:

  1. If you are looking to do this on the fly on an arbitrary device (vs. in a lab setting), you will need to follow Jeffrey's recommendation, because other apps can consume bandwidth that would be reported by getTotalRxBytes().

  2. This tests download speed from this host. If that is the host you will be communicating with for "real stuff", that's cool. Or, if you just generically need an idea of download speed, it's OK. But testing download speed from Site A and assuming that it will be accurate for Site B will be unreliable, as Site A and Site B might not even be on the same continent.

  3. If you expect to do this a lot, the owner of the host you are testing against may be mildly irritated at the bandwidth expense, excessive log entries, etc. Ideally, you would only do this against something you own.

  4. For metered data plans, 200KB might irritate the device owner.

  5. All the standard caveats regarding Internet access (e.g., server may be down) and mobile devices (e.g., user might start on WiFi and move out of range, drastically changing your download ability) apply.

All that being said, doing a download is the only real way to gauge download speeds.

Forthcoming answered 4/9, 2012 at 11:40 Comment(1)
with respect with the first point: "other apps can consume bandwidth that would be reported by getTotalRxBytes()" if the idea is to measure the band width then it is OK to use getTotalRxBytes(), cause if other apps consume bandwith you wanna consider that on your calculation.Nuthatch
C
3

Use the code below. I used it for measuring download speed. You don't need to save the file for the purpose of measuring download speed. You also probably don't need to use OkHttp. I used it because it was used in our project.

    String downloadURL = "http://test.talia.net/dl/1mb.pak";

    MediaType FILE = MediaType.parse("multipart/form-data;");

    OkHttpClient downloadClient = new OkHttpClient().newBuilder()
            .build();

    Request download = new Request.Builder()
            .url(downloadURL)
            .build();

    downloadClient.newCall(download).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if(response!=null) {
                long startTime = System.currentTimeMillis();
                InputStream is = response.body().byteStream();
                BufferedInputStream bis = new BufferedInputStream(is);
                long size = 0;
                int red = 0;
                byte[] buf = new byte[1024];
                while ((red = bis.read(buf)) != -1) {
                    size += red;
                }
                long endTime = System.currentTimeMillis();
                double rate = (((size / 1024) / ((endTime - startTime) / 1000.0)) * 8);
                rate = Math.round( rate * 100.0 ) / 100.0;
                String ratevalue;
                if(rate > 1000)
                    ratevalue = String.valueOf(rate / 1024).concat(" Mbps");
                else
                    ratevalue = String.valueOf(rate).concat(" Kbps");
                if(is!=null) {
                    is.close();
                }
                if(bis!=null) {
                    bis.close();
                }
                Log.d("download", "download speed = " + ratevalue);
            }
        }
    });
Charitacharitable answered 23/3, 2017 at 12:51 Comment(1)
Using 1000.0 instead 1000 in rate calculation is more accurate because (endTime - startTime) / 1000 = 1.82 = 1, when those 0.82 is very important in our case.Tonsillectomy
G
0

There are many sampling methodologies , there is no one "true" speed. You can check following standards to give you more idea what is the recommended way:

https://itu.int/en/ITU-T/C-I/Pages/IM/Internet-speed.aspx

https://itu.int/itu-t/recommendations/rec.aspx?rec=q.3960

https://itu.int/ITU-T/recommendations/rec.aspx?rec=14125

https://tools.ietf.org/pdf/rfc6349.pdf

Your proposed code tests the speed using 1 thread. This is not recommended way as it will not maximize the full capacity of the internet connection. Most of the standards recommend multithreaded testing.

You can also use our Android SDK which should do what you need and is compliant with ITU standard:

https://github.com/speedchecker/speedchecker-sdk-android

Glanders answered 13/11, 2020 at 12:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.