NanoHTTPD. Cache InputStream to file and continue streaming
Asked Answered
S

0

6


I want to cache data while playing it in MediaPlayer. As I read, there is one way to do it - create own local http server and set local url to MediaPlayer's setDataSource(String path).

I am using NanoHTTPD as a local server. There is code of serve function:


    @Override
    public Response serve(String uri, Method method, Map headers, Map parms, Map files)
    {
        try
        {
            // delete / character
            URL url = new URL(uri.substring(1));
            URLConnection connection = url.openConnection();
            connection.connect();

            File cacheFolder = new File(Environment.getExternalStorageDirectory(), "TracksFlowCacheNew");
            Log.e("RelayServer", "Cache to file " + Utils.md5(url.toExternalForm()));
            RelayInputStream ris = new RelayInputStream(connection.getInputStream(), new FileOutputStream(new File(cacheFolder, Utils.md5(url.toExternalForm()))));


            return new Response(Response.Status.OK, NanoHTTPD.MIME_DEFAULT_BINARY, ris);
        }
        catch(MalformedURLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch(FileNotFoundException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch(IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }


RelayInputStream extending InputStream. I am trying to cache data there:


    private class RelayInputStream extends InputStream
    {
        private InputStream mInputStream = null;
        private OutputStream mOutputStream = null;

        public RelayInputStream(InputStream is, OutputStream os)
        {
            mInputStream = is;
            mOutputStream = os;
        }

        @Override
        public int available() throws IOException
        {
            Log.e("available", "available = " + mInputStream.available());
            mInputStream.mark(mInputStream.available());
            return mInputStream.available();
        }

        @Override
        public int read(byte[] buffer) throws IOException
        {
            Log.e("read", "buffer = " + buffer.toString());
            mOutputStream.write(buffer);
            return mInputStream.read(buffer);
        }

        @Override
        public int read(byte[] buffer, int offset, int length) throws IOException
        {
            Log.e("read", "buffer = " + buffer.toString() + "; offset = " + offset + "; length = " + length);
            mOutputStream.write(buffer, offset, length);
            return mInputStream.read(buffer, offset, length);
        }

        @Override
        public int read() throws IOException
        {
            Log.e("read", "no data");
            byte[] b = new byte[1];
            mInputStream.read(b);
            mOutputStream.write(b);
            mInputStream.close();
            mOutputStream.close();
            return b[0] & 0xff;
        }
    }

But RelayInputStream's available returns only few downloaded bytes. So, there is only little part of data cached and returned to the media player. So, what am I doing wrong? How to forward and cache all stream?

Selfpreservation answered 23/7, 2013 at 11:50 Comment(12)
Sorry, but where are you trying to cache something? Please explain your code.Bouffe
available() returns the number of bytes you can read. But available() is not correct in many situations as you can see in the help too. You are not caching anything. For caching you would need a buffer. Now it looks if you wanted to cache to file but you are not doing that. You would need at least one thread that reads from original url and saved data to a buffer or file. Then your three read functions could read from that buffer or file.Bouffe
@Bouffe Cant remember, I was learning android. Seems it shall read data from InputStream use data in MediaPlayer and write it to file. I tried to make music player app(music service client), and trying to find a way to save music stream to storage while playing. But service dies before I finish that app)Selfpreservation
mOutputStream.write(buffer);. You have that statement in two read() functions. But that buffer is empty as read() is a request to fill that buffer. So that statement there is not ok.Bouffe
way to save music stream to storage while playing. That is something quite different from caching. Please explain better what you want.Bouffe
@Bouffe I ask that question 2 years ago and now it is not actual, there is errors in code, like writing empty buffer, u told. But the problem: how to cache music for playing. So I wanna to start network stream reading, save 15 sec to file and start to play music from that file. That code was first approach to do that. MediaPlayer need InputStream as source, so I create InputStream where every read method reads data from original network stream, saves data to output and return buffer to MediaPlayer. Smth like that.Selfpreservation
Ok. You start to play music from that file but after 15 seconds the file is played. How to continue?Bouffe
@Bouffe so there will be 2 parallel threads as u noticed :) One will load data, another will play.Selfpreservation
Yes. But you need to add only one thread as i said before. Nano cares for the other.Bouffe
@Bouffe yep. It was not nano mistake, it was mineSelfpreservation
@Selfpreservation did you somehow managed to solve this?Shermy
@AkashSingh No, I didn't. But there is a major mistake, as noticed above: in read methods, except last one, I did mOutputStream.write(buffer), while buffer is known to be empty. So maybe you shall swap mInputStream.read(buffer) and mOutputStream.write(buffer) and it will work.. But idk.Selfpreservation

© 2022 - 2024 — McMap. All rights reserved.