I'm serving .mp4 videos and .mp3 audios using private download (field's upload destination: Private files), and they play OK on native html5 player, but seeking doesn't work, as in I can't jump to the middle of a video or audio.

This happens on Chrome and doesn't happen on Firefox. Also no problem playing and jumping on public download or when the file is saved on local drive and played from there.

After comparing the response headers in several different scenarios I have concluded that the only consistent difference between working and non-working is that Accept-Ranges and Last-Modified headers are missing when seeking is not working. These can be added at hook_file_download but then the media won't play at all.

This a pain to test with Chrome Developer Tools > Networking as Chrome pulls old headers from its memory, so you never know which input is producing which output.

Solution

Install https://www.drupal.org/project/resumable_download. Despite its name and the fact that it's at beta1 (it gives some notices) it does the job. It takes completely care of feeding the media to the browser.

Edit: If the module doesn't work, check out this patch: https://www.drupal.org/node/2362393

up vote 1 down vote accepted

Problem

Chrome makes multiple HTTP request with Range header for media file and expects HTTP Content-Range and Content-Length response header with 206 Partial Content status (read this). If server send '200 OK' status Chrome will not play the media file, but Firefox will. If server send '200 OK' status with response header 'Accept-Ranges: none' then Chrome will play media file, but jumping will not work. I assume you have implemented hook_file_download() already. That hook should return array of appropriate HTTP headers. It's enough to return Accept-Ranges header (only if your module should handle the media file and current user has permission):

return array(
  'Accept-Ranges' => 'bytes',
);

Solution - Drupal 7

Accept-Ranges response header with value 'bytes' is a signal to client that server supports Range request. If you don't want to support Range request you should use 'none' instead of 'bytes'. There is no server support for Range request for private files. Therefore you should install Resumable Download module which will setup other HTTP response headers like: Content-Range, Content-Length and ETag, and set HTTP status 206 Partial Content. Drupal core module File will setup other HTTP response header like Content-Type.

  • Thanks. I added headers with hook_file_download. No success yet, though. I didn't install Resumable Download, but I copied some of those drupal_add_http_header calls from there. I edited the questions to describe the current situation. – Kari Kääriäinen Jun 18 '17 at 23:15
  • 1
    If you set Status header to '206 Partial Content' then you need (your server need) to deliver chunks of requested bytes. For example, Chrome sends the first request for a mp4 file, server respond with Accept-Ranges: bytes, Status: 206 Partial Content. This is a signal for Chrome to send another request for first n bytes (n < total bytes of mp4 file), but there is nothing on server side to deliver n bytes. So, you need to implement delivering requested bytes or install some module that has already implemented the process. – purplemind Jun 25 '17 at 14:35

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.