6

I'm playing an audio file using jlGui's BasicPlayer (it's based on Javasound). The file is in a Samba share and I'm using Jcifs to access it. It gives me an InputStream.

NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication( ... );

SmbFile f = new SmbFile( ... );
SmbFileInputStream audioIn = new SmbFileInputStream(f);

int bufSize = 8096;//should I use f.length() here?
audioBIS = new BufferedInputStream(audioIn, bufSize);

audioBIS.mark(f.length());

    //call BasicPlayer
play(audioBIS);

I need to be able to position the pointer anywhere in the file, just like any common player. The only solution I could think of was to use a BufferedInputStream and a combination of mark/reset/skip everytime I need to reposition the pointer. As soon as I open the file and get the Stream, I call the mark() method, so that a subsequent reset() will reposition me at the beginning. Then with skip() I can go where I want.

audioBIS.reset();
audioBIS.skip(newBytePosition);

My problem is that the skip() call works as desired only if I specify a buffer big enough to contain the whole file.

Is there a more efficient way to do this?

Giuseppe
  • 597
  • 7
  • 26

2 Answers2

2

I've been down the excact same path as you are now. The case was that we had a server (and a SMB share) holding thousands of audio files. These files needed to be playable in an application.

I started out with jCifs, and modified the source of BasicPlayer to deal with SmbFile the same way it would deal with File. It worked alright, but when it comes to seeking/skipping it does not really blow you away. As long as you've got a good connection to the server, you should be alright.

I ended up ditching that solution, and instead installed tomcat6 on the server and deployed a small and simple servlet that would allow requests to be made for a file at a given position. The client machine would then take the response as an InputStream and pass that on to BasicPlayer. It works much better, and the playback is instant. The code is a little more than what is reasonable to paste here, but I'd be willing to share it with you if you are interested.

sbrattla
  • 5,274
  • 3
  • 39
  • 63
  • Your solution sounds very interesting, but I don't have enough reach on the server side to install tomcat. Anyway, I could think of a wrapper of BasicPlayer which does more or less the same thing, taking care of seek and getTime functions. Just a question. How do you generate an Inputstream based on a given offset? The answer given [here](http://stackoverflow.com/questions/5923817/how-to-clone-an-inputstream) is inspiring and also implies caching, but I'm worried about the overhead I would introduce making copies of huge arrays. – Giuseppe Sep 05 '12 at 08:29
  • When you say InputStream based on a given offset, are you then still talking about jCifs (SmbFile) and offset in bytes? – sbrattla Sep 05 '12 at 12:25
  • I was referring to the part where you say "The client machine would then take the response as an InputStream". Don't you mean the server responds with an inputstream which starts at the desired position? – Giuseppe Sep 05 '12 at 12:44
  • Yes, my application would call, say, http://mediaserver/stream?fid=50&pos=1000 where fid would be the file id and pos would be the position in miliseconds. The servlet would then take this request, find the bytes offset that corresponds to the provided miliseconds offset. Based on the bytes offset, I create an instance of RandomAccessFile for the file (corresponding to fid) and use RandomAccessFile#seek to get to the bytes position. From there i simply return an BufferedOutputStream to the client application. Its quick (matter of few miliseconds) and has worked well for a year. – sbrattla Sep 05 '12 at 12:55
  • Could you show us the servlet code, I'm interested in how this is done. – dessalines Jun 19 '15 at 20:49
0

As an alternative. You can always just close the stream and recreate it. Seems to go fast and you are back to position 0 if needed.

So keep track on where you are. As long as you move forward, keep the stream and jump with skip(). Once you need to go back again, close that stream and create a new and skip() to the wanted position.

Unless the application is heavy on backskipping all the time you should be ok.

Wrap that up in a new nice custom stream and you have a stream supporting going back and forth.

Wolf5
  • 16,600
  • 12
  • 59
  • 58