Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NanoHttpd server cannot stream large videos on android

NanoHttpd server code can be found here.

I'm starting a new Thread in a service that uses NanoHttpd server to stream large videos (about 150mb) but it just pauses right while the loading dialog is shown. I tried increasing and decreasing the buffer reads to no avail. It seems that the server cannot run properly on an Android device.

Same code works fine when I start the server via desktop application. I can stream more than 150mb. When running the server from the phone, I only tried 20mb files and they were good too. However I need to stream much more than that.

like image 537
josephus Avatar asked Feb 29 '12 05:02

josephus


1 Answers

In case others come across this and want to see what the actual code is in this solution, I'm posting my code here. I'm using my Android device to stream a video file from the SD card for a Chromecast request. Using this code, I'm able to start the stream in the middle and/or seek to a specific location in the stream.

@Override
@SuppressWarnings("deprecation")
public Response serve(String uri, Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files) {
    String mimeType = getMimeType();
    String currentUri = getCurrentUri();
    if (currentUri != null && currentUri.equals(uri)) {
        String range = null;
        Log.d(TAG, "Request headers:");
        for (String key : headers.keySet()) {
            Log.d(TAG, "  " + key + ":" + headers.get(key));
            if ("range".equals(key)) {
                range = headers.get(key);
            }
        }
        try {
            if (range == null) {
                return getFullResponse(mimeType);
            } else {
                return getPartialResponse(mimeType, range);
            }
        } catch (IOException e) {
            Log.e(TAG, "Exception serving file: " + filePath, e);
        }
    } else {
        Log.d(TAG, "Not serving request for: " + uri);
    }

    return new Response(Response.Status.NOT_FOUND, mimeType, "File not found");
}

private Response getFullResponse(String mimeType) throws FileNotFoundException {
    cleanupStreams();
    fileInputStream = new FileInputStream(filePath);
    return new Response(Response.Status.OK, mimeType, fileInputStream);
}

private Response getPartialResponse(String mimeType, String rangeHeader) throws IOException {
    File file = new File(filePath);
    String rangeValue = rangeHeader.trim().substring("bytes=".length());
    long fileLength = file.length();
    long start, end;
    if (rangeValue.startsWith("-")) {
        end = fileLength - 1;
        start = fileLength - 1
                - Long.parseLong(rangeValue.substring("-".length()));
    } else {
        String[] range = rangeValue.split("-");
        start = Long.parseLong(range[0]);
        end = range.length > 1 ? Long.parseLong(range[1])
                : fileLength - 1;
    }
    if (end > fileLength - 1) {
        end = fileLength - 1;
    }
    if (start <= end) {
        long contentLength = end - start + 1;
        cleanupStreams();
        fileInputStream = new FileInputStream(file);
        //noinspection ResultOfMethodCallIgnored
        fileInputStream.skip(start);
        Response response = new Response(Response.Status.PARTIAL_CONTENT, mimeType, fileInputStream);
        response.addHeader("Content-Length", contentLength + "");
        response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength);
        response.addHeader("Content-Type", mimeType);
        return response;
    } else {
        return new Response(Response.Status.RANGE_NOT_SATISFIABLE, HTML_MIME_TYPE, rangeHeader);
    }
}
like image 68
mikejonesguy Avatar answered Oct 03 '22 17:10

mikejonesguy