Hey all I have the following Java code I did in Android Studio that I am needing some help with.
I am needing to be able to load a shared file from my router (It's running OpenWRT/Luci) with the Samba file sharing turned on. I have tested the code out below to make sure it's finding the file and I can confirm It can find it when it checks for SMB file found? and it comes back true.
When loading local file:
However, the issue is that when I switch over to getting the SMB video it does not load like the other tests that I did - loading it up from local storage.
When loading from SMB file:
My full code that I am currently using:
package com.example.smbvidoverhttp; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.MediaController; import android.widget.VideoView; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.util.HashMap; import java.util.Map; import fi.iki.elonen.NanoHTTPD; import jcifs.smb.NtlmPasswordAuthentication; import jcifs.smb.SmbAuthException; import jcifs.smb.SmbFile; import jcifs.smb.SmbFileInputStream; import jcifs.smb.SmbFileOutputStream; public class MainActivity2 extends AppCompatActivity { Button btn; Button btn2; VideoView videoView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = findViewById(R.id.button); btn2 = findViewById(R.id.button2); videoView = findViewById(R.id.videoView); MediaController mediaController = new MediaController(this); videoView.setMediaController(mediaController); btn.setOnClickListener(v -> { try { VideoServer blah = new VideoServer(); blah.start(); } catch (IOException e) { throw new RuntimeException(e); } }); btn2.setOnClickListener(v -> { try { videoView.setVideoURI(Uri.parse("http://127.0.0.1:7777/bun33s.mp4")); //videoView.requestFocus(); videoView.start(); } catch (Exception e) { Log.d("", "ERROR: " + e.getMessage()); } }); } @Nullable @SuppressWarnings("JavaReflectionMemberAccess") public String findSDCardPath() { try { final Class<?> surfaceControlClass = Class.forName("android.os.storage.StorageManager"); Object StorageServ = getApplicationContext().getSystemService(Context.STORAGE_SERVICE); Method method1 = surfaceControlClass.getMethod("getVolumePaths"); method1.setAccessible(true); String[] volumes = (String[]) method1.invoke(StorageServ); if (volumes.length > 1) { Log.d("smbTest", "External: " + volumes[1]); return volumes[1]; } else { Log.d("smbTest", "Internal: " + volumes[0]); return volumes[0]; } } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | IllegalAccessException ex) { Log.d("smbTest", "ERROR: " + ex.getMessage()); } return null; } public class VideoServer extends NanoHTTPD { String filePath = ""; public VideoServer() { super(7777); } @Override public Response serve(IHTTPSession session) { final String theVidName = ((HTTPSession) session).getUri(); // /bun33s.mp4 String range = null; Map<String, String> headers = session.getHeaders(); for (String key : headers.keySet()) { if ("range".equals(key)) { range = headers.get(key); break; } } if (range != null) { try { return getPartialResponse("video/mp4", range); } catch (IOException e) { throw new RuntimeException(e); } } else { return responseVideoStream(session, filePath); } } public Response responseVideoStream(IHTTPSession session, String videopath) { try { NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(null, "user here", "password here"); SmbFile source = new SmbFile("smb://192.168.8.1/GL-Samba/bun33s.mp4", auth); SmbFileInputStream inputStream = new SmbFileInputStream(source); boolean b; try { b = source.exists(); Log.d("", "SMB file found? " + b); } catch(SmbAuthException e) { Log.d("", "Exception caught while calling SmbFile#exists(): " + e.getMessage()); } //InputStream in = source.getInputStream(); //FileInputStream fis = new FileInputStream(videopath); return newChunkedResponse(Response.Status.OK, "video/mp4", inputStream); } catch (MalformedURLException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } 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; FileInputStream fileInputStream = new FileInputStream(file); fileInputStream.skip(start); Response response = newFixedLengthResponse(Response.Status.PARTIAL_CONTENT, mimeType, fileInputStream, contentLength); response.addHeader("Content-Length", contentLength + ""); response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength); response.addHeader("Content-Type", mimeType); return response; } else { return newChunkedResponse(Response.Status.INTERNAL_ERROR, "text/html", null); } } } }
For testing it out I'm just using the ADB with the correct device number to send a http request to the built in browser:
And like I said, it plays when I test it out loading a local file on the device but wont play when using the SMB file.adb -s 25131HFDD6222C shell am start -a android.intent.action.VIEW -d http://127.0.0.1:7777/bun33s.mp4
What am I missing?