1

I'm writing a Ruby on Rails application which allows a user to upload an mp3 file, then play it back. I have it working to the point where a user can do those things, BUT there is an issue when seeking through the song. If a user seeks ahead (or lets it play) to a spot in the song, usually about 2/3 or 3/4 the way through the song, then attempts to seek back to the beginning (for example 0:20), the play timer will go to 0:20, like it should but the actual audio will start over again as if the user seeked to 0:00.

Right now I'm simply attempting to get the song to play in chrome's basic html5 mp3 player that it uses when passed an mp3 file. This is the code I'm using to serve up the file, hopefully with all the correct headers:

  file_begin = 0
  file_size = @media.file_file_size 
  file_end = file_size - 1

  if !request.headers["Range"]
    status_code = "200 OK"
  else
    status_code = "206 Partial Content"
    match = request.headers['range'].match(/bytes=(\d+)-(\d*)/)
    if match
      file_begin = match[1]
      file_end = match[1] if match[2] && !match[2].empty?
    end
    response.header["Content-Range"] = "bytes " + file_begin.to_s + "-" + file_end.to_s + "/" + file_size.to_s
  end
  response.header["Content-Length"] = (file_end.to_i - file_begin.to_i + 1).to_s
  response.header["Last-Modified"] = @media.file_updated_at.to_s

  response.header["Cache-Control"] = "public, must-revalidate, max-age=0"
  response.header["Pragma"] = "no-cache"
  response.header["Accept-Ranges"]=  "bytes"
  response.header["Content-Transfer-Encoding"] = "binary"
  send_file(DataAccess.getUserMusicDirectory(current_user.public_token) + @media.sub_path, 
            :filename => @media.file_file_name,
            :type => @media.file_content_type, 
            :disposition => "inline",
            :status => status_code,
            :stream =>  'true',
            :buffer_size  =>  4096)

I'd appreciate any insight into this problem. I feel like I'm so close because it pretty much all works, except for seeking near the beginning causing a new request.

Thanks!

Garrett
  • 146
  • 2
  • 6
  • I was wondering if Webrick's send_file doesn't take into account the Content-Range header, so instead of sending the portion of the song that the user seeked to, it just resends the entire a file again? Is there a way to make webrick and send_file adhere to the Content-Range header, so it only sends a portion of the file instead of the entire thing? – Garrett Sep 30 '11 at 17:05

1 Answers1

0

Is re-invention of the wheel a requirement? The reason I ask is you could have simply allowed the user to upload the MP3 file and used html5's feature as you're targeting Chrome. Paperclip could have taken care of the upload, to somewhere preferable in the public directory, and you just hand off that path to the tag.

Crazy ideas removed from my comments (below) to prevent confusing other SO readers. See my last comment for a solution but Amazon S3 is pretty much the best solution.

Community
  • 1
  • 1
Michael De Silva
  • 3,808
  • 1
  • 20
  • 24
  • I see what you're saying, and I do use paperclip for the upload, but I want the playing to be restricted by user, a user can only listen to songs they've uploaded. So to restrict the use, I don't put it in the public directory, because then any user could listen to any file. – Garrett Sep 30 '11 at 14:15
  • So rather then completely hide the files, I should just obscure their location enough that they're difficult to find? That's a possibility and wouldn't be difficult to implement at all. I just am a little hesitant about the idea of having all the user files in the public folder, because that could potentially open up the files to be accessed in ways I don't want them to be. – Garrett Sep 30 '11 at 16:41
  • Well one alternative would be to serve the assets from Amazon S3. – Michael De Silva Sep 30 '11 at 17:10
  • Yup, ignore my crazy ideas - stay away from public. [See this link instead](http://www.therailsway.com/2009/2/22/file-downloads-done-right). – Michael De Silva Sep 30 '11 at 17:16