Unable to jump to a specific spot (seek) when mp4 or mp3 is in private field 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
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' =&gt; '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.