package com.simplecity.amp_library.http; import android.util.Log; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import fi.iki.elonen.NanoHTTPD; public class HttpServer { private static final String TAG = "HttpServer"; private static HttpServer sHttpServer; private NanoServer server; String audioFileToServe; byte[] imageBytesToServe; FileInputStream audioInputStream; ByteArrayInputStream imageInputStream; private boolean isStarted = false; public static HttpServer getInstance() { if (sHttpServer == null) { sHttpServer = new HttpServer(); } return sHttpServer; } private HttpServer() { server = new NanoServer(); } public void serveAudio(String audioUri) { if (audioUri != null) { audioFileToServe = audioUri; } } public void serveImage(byte[] imageUri) { if (imageUri != null) { imageBytesToServe = imageUri; } } public void start() { if (!isStarted) { try { server.start(); isStarted = true; } catch (IOException e) { Log.e(TAG, "Error starting server: " + e.getMessage()); } } } public void stop() { if (isStarted) { server.stop(); isStarted = false; cleanupAudioStream(); cleanupImageStream(); } } private class NanoServer extends NanoHTTPD { NanoServer() { super(5000); } @Override public Response serve(IHTTPSession session) { if (audioFileToServe == null) { Log.e(TAG, "Audio file to serve null"); return newFixedLengthResponse(Response.Status.NOT_FOUND, "text/html", "File not found"); } String uri = session.getUri(); if (uri.contains("audio")) { try { File file = new File(audioFileToServe); Map<String, String> headers = session.getHeaders(); String range = null; for (String key : headers.keySet()) { if ("range".equals(key)) { range = headers.get(key); } } if (range == null) { range = "bytes=0-"; session.getHeaders().put("range", range); } long start; long end; long fileLength = file.length(); String rangeValue = range.trim().substring("bytes=".length()); if (rangeValue.startsWith("-")) { end = fileLength - 1; start = fileLength - 1 - Long.parseLong(rangeValue.substring("-".length())); } else { String[] ranges = rangeValue.split("-"); start = Long.parseLong(ranges[0]); end = ranges.length > 1 ? Long.parseLong(ranges[1]) : fileLength - 1; } if (end > fileLength - 1) { end = fileLength - 1; } if (start <= end) { long contentLength = end - start + 1; cleanupAudioStream(); audioInputStream = new FileInputStream(file); audioInputStream.skip(start); Response response = newFixedLengthResponse(Response.Status.PARTIAL_CONTENT, getMimeType(audioFileToServe), audioInputStream, contentLength); response.addHeader("Content-Length", contentLength + ""); response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength); response.addHeader("Content-Type", getMimeType(audioFileToServe)); return response; } else { return newFixedLengthResponse(Response.Status.RANGE_NOT_SATISFIABLE, "text/html", range); } } catch (IOException e) { Log.e(TAG, "Error serving audio: " + e.getMessage()); e.printStackTrace(); } } else if (uri.contains("image")) { cleanupImageStream(); imageInputStream = new ByteArrayInputStream(imageBytesToServe); return newFixedLengthResponse(Response.Status.OK, "image/png", imageInputStream, imageBytesToServe.length); } Log.e(TAG, "Returning NOT_FOUND response"); return newFixedLengthResponse(Response.Status.NOT_FOUND, "text/html", "File not found"); } } void cleanupAudioStream() { if (audioInputStream != null) { try { audioInputStream.close(); } catch (IOException ignored) { } } } void cleanupImageStream() { if (imageInputStream != null) { try { imageInputStream.close(); } catch (IOException ignored) { } } } private final Map<String, String> MIME_TYPES = new HashMap<String, String>() {{ put("css", "text/css"); put("htm", "text/html"); put("html", "text/html"); put("xml", "text/xml"); put("java", "text/x-java-source, text/java"); put("md", "text/plain"); put("txt", "text/plain"); put("asc", "text/plain"); put("gif", "image/gif"); put("jpg", "image/jpeg"); put("jpeg", "image/jpeg"); put("png", "image/png"); put("mp3", "audio/mpeg"); put("m3u", "audio/mpeg-url"); put("mp4", "video/mp4"); put("ogv", "video/ogg"); put("flv", "video/x-flv"); put("mov", "video/quicktime"); put("swf", "application/x-shockwave-flash"); put("js", "application/javascript"); put("pdf", "application/pdf"); put("doc", "application/msword"); put("ogg", "application/x-ogg"); put("zip", "application/octet-stream"); put("exe", "application/octet-stream"); put("class", "application/octet-stream"); }}; String getMimeType(String filePath) { return MIME_TYPES.get(filePath.substring(filePath.lastIndexOf(".") + 1)); } }