Serving files with html5 audio

Showing 1-12 of 12 messages
Serving files with html5 audio Hanna 3/15/12 7:12 AM
Hi,

I'm having problems serving audio files in Lift, to be played using the html5 audio element.

Here's an example of the audio element:

 <audio>
  <source type="audio/mpeg" src="/virtual-path/audio.mp3" />
 </audio>


The audio files are uploaded by users, and stored on the web server. When a request is received, the exact location of the file is computed by Boot before the file is loaded, and a response is sent.

After some first failed attempts, a response looking something like this seemed to work (with Chrome and IE9). (The code is in LiftRules.dispatch.append { ... } )

// ba: a byte array with the file contents
InMemoryResponse(ba
,List("Content-Type" -> "audio/mpeg"
      ,"Accept-Ranges" -> "bytes"
      ,"Content-Length" -> ba.length.toString
)
,Nil
,200)



But this doesn't work well with larger files, so I tried using a StreamingResponse instead. (The test file is 6.5M.) A response similar to that below works for playing the audio file once, if it's not paused during playback.

// stream: an input stream with the file contents
// file: java.io.File
StreamingResponse(stream
                ,() => {} // I've tried stream.close here, too
,file.length
,List("Content-Disposition" -> ("attachment; " + file.getName))
,Nil
,200) // I've tried with 206 here, too

But with the StreamingResponse, the file cannot be played more than once, and it's very sensitive to pausing or moving the cursor. I've tested various header contents as well, but Content-Disposition is what I've found in examples.

If I put the same audio file in static, and let Jetty handle the response, it works just fine.

Does anyone have any suggestions on how to write the response? Or is there any way to just compute the exact location of the file, and pass a java input stream (or similar) over to Jetty instead, where it seems to work already?

Or maybe I'm asking the wrong question. Any feedback would be appreciated.

(If needed, I can put together a sample Lift app with a few examples.)

Cheers,
/Hanna


Re: [Lift] Serving files with html5 audio David Pollak 3/15/12 1:56 PM
Hanna,

At this point, Lift does not support chunked HTTP response (I don't know the right words for the feature, but it allows an HTTP request to ask for only a range of a file.)  That would likely make your audio file play back more evenly.

Please open a ticket at http://ticket.liftweb.net and link to this thread.

If anyone else has ideas/suggestions, please post them.

Thanks,

David



--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code



--
Visi.Pro, Cloud Computing for the Rest of Us http://visi.pro
Lift, the simply functional web framework http://liftweb.net


This message has been hidden because it was flagged for abuse.
Re: [Lift] Serving files with html5 audio Jeppe Nejsum Madsen 3/16/12 1:08 AM
Hanna <han....@gmail.com> writes:


[...]

> If I put the same audio file in static, and let Jetty handle the response,
> it works just fine.

Would be interesting to see the HTTP flow in this case to determine if
it uses Chunked transfer encoding....

> Does anyone have any suggestions on how to write the response? Or is there
> any way to just compute the exact location of the file, and pass a java
> input stream (or similar) over to Jetty instead, where it seems to work
> already?

You could just map a path to be handled directly by jetty, bypassing
lift, and then store the content there.

/Jeppe

Re: [Lift] Serving files with html5 audio Damian Helme 3/16/12 5:43 AM
I think David's  'chunked HTTP response' is referring to HTTP 'Range' requests.

I found this example Java code a while back for handling Range requests:


I used this as a starting point for coding up my own Lift version.

I've posted my code here: https://gist.github.com/2049865 if you want to take a look as a starting point. It's a while since I've visited it and it's in need of a bit of refactoring. I can't remember how far I got with testing (the project has been parked for the moment & hasn't gone live), so proceed with caution ... 






Re: [Lift] Serving files with html5 audio David Pollak 3/16/12 8:45 AM
Thank you very much!!  If you're in London, come on over to the Slaughtered Lamb tonight and I'll buy you a beer!






--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code
Re: [Lift] Serving files with html5 audio Damian Helme 3/16/12 9:04 AM
Thanks - would have loved to but am back in Cambridge now. I might keep it as a credit for next time, though ;-)
Re: [Lift] Serving files with html5 audio David Pollak 3/16/12 9:24 AM
Definitely!



On Mar 16, 2012, at 4:04 PM, Damian Helme <damia...@gmail.com> wrote:

Thanks - would have loved to but am back in Cambridge now. I might keep it as a credit for next time, though ;-)

--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code
Re: [Lift] Serving files with html5 audio Hanna 3/19/12 7:42 AM
Hi, thanks for all replies!

I think I'll give bypassing the audio to Jetty a try, then. If you could point me in the right direction, such as an example to use as a starting point, that would be very much appreciated.
(And if it involves editing the webdefault.xml, how do I do that when running jetty in dev mode from sbt?)

Damian: thanks for creating the ticket.

Cheers,
Hanna

Re: [Lift] Serving files with html5 audio Damian Helme 3/20/12 10:14 AM
Hi,
Adding something like:

LiftRules.liftRequest.append { 
  case r @ Req("mediadir" :: filename :: Nil,_,_) => { 
      debug("passing request onto container: " +  r)
      false
  }
}

in your Boot.scala will pass matching requests onto Jetty, but there are quite a few more issues to iron out (like making sure you don't try to upload files into a directory in your WAR file). There are plenty of threads in this group that discuss various approaches.

Re: [Lift] Serving files with html5 audio Richard Dallaway 3/21/12 4:29 AM
This would make a great cookbook.liftweb.net recipe if anyone wants to take it on.  I'd suggest the Pipeline chapter.

Re: [Lift] Serving files with html5 audio Hanna 3/23/12 3:51 AM
Thanks Damian, that was enough to get me started!

I managed to make a standalone Jetty environment handle files (Jetty deployed from this example ), by creating an xml file with the following content in a folder "contexts":

<Configure class="org.mortbay.jetty.servlet.Context">
  <Set name="contextPath">/jettybypass</Set>
  <Set name="resourceBase">jettybypasstest</Set>
  <Call name="addServlet">
    <Arg>org.mortbay.jetty.servlet.DefaultServlet</Arg>
    <Arg>/</Arg>
  </Call>
</Configure>

But I couldn't find out how to do the same thing when running Jetty from within sbt.

Another thing is that I'd want to check some access rights as well before passing the request onto Jetty, but after what I've read in other threads, it seems difficult to do that in a stateful context (within a user session), am I right?

Hanna