1

I have converted a single page HTML5 Cordova app into a PWA. The app uses jPlayer extensively to play mp3 files. I am using a variant of the circular jPlayer here: http://jplayer.org/latest/demo-05/. The circle player has a circular progress bar that can also be used to scrub backwards and forwards through the track.

Everything works fine in PWA mode until I cache the mp3 with Workbox (version 4.3.1). Then scrubbing fails. I can grab the scrub bar and move it but when I release it the track restarts from the beginning. This happens if I use precaching for the mp3 or a dedicated audio cache for all mp3 files. Turn off caching, update the service worker and refresh -- and I can scrub. Turn on caching and refresh and scrubbing fails.

I would really like scrubbing to work with cached audio files so that the app can work offline.

This seems similar in nature to Make mp3 seekable PHP.

daffinm
  • 177
  • 1
  • 13

1 Answers1

2

I'm excerpting this from the Workbox documentation's recipe for serving cached audio and video.

There are a few wrinkles in how some browsers request media assets (e.g., the src of a <video> or <audio> element) that can lead to incorrect serving behavior unless you take specific steps when configuring Workbox.

Full details are available in this GitHub issue discussion; a summary of the important points is:

  • Workbox must be told to respect Range request headers by adding in the workbox-range-requests plugin to the strategy used as the handler.

  • The audio or video element needs to opt-in to CORS mode using the crossOrigin attribute, e.g. via .

  • If you want to serve the media from the cache, you should explicitly add it to the cache ahead of time. This could happen either via precaching, or via calling cache.add() directly. Using a runtime caching strategy to add the media file to the cache implicitly is not likely to work, since at runtime, only partial content is fetched from the network via a Range request.

Putting this all together, here's an example of one approach to serving cached media content using Workbox:

<!-- In your page: -->
<!-- You currently need to set crossOrigin even for same-origin URLs! -->
<video src="movie.mp4" crossOrigin="anonymous"></video>
// In your service worker:
// It's up to you to either precache or explicitly call cache.add('movie.mp4')
// to populate the cache.
//
// This route will go against the network if there isn't a cache match,
// but it won't populate the cache at runtime.
// If there is a cache match, then it will properly serve partial responses.
workbox.routing.registerRoute(
  /.*\.mp4/,
  new workbox.strategies.CacheFirst({
    cacheName: 'your-cache-name-here',
    plugins: [
      new workbox.cacheableResponse.Plugin({statuses: [200]}),
      new workbox.rangeRequests.Plugin(),
    ],
  }),
);

If you plan on precaching the media files, then you need to take an extra step to explicitly route things so that they're read from the precache, since the standard precache response handler won't use the range request plugins:

workbox.routing.registerRoute(
  /.*\.mp4/,
  new workbox.strategies.CacheOnly({
    cacheName: workbox.core.cacheNames.precache,
    plugins: [
      new workbox.rangeRequests.Plugin(),
    ],
    // This is needed since precached resources may
    // have a ?_WB_REVISION=... URL param.
    matchOptions: {
      ignoreSearch: true,
    }
  }),
);

// List this *after* the preceding runtime caching route.
workbox.precaching.precacheAndRoute([...]);
Jeff Posnick
  • 53,580
  • 14
  • 141
  • 167
  • It worked!! Many thanks Jeff for a truly educational and comprehensive answer :) I can now scrub through audio when offline. All mp3s are pre-cached. I'll post my config in an answer below since I could not find any explicit docs on implementing your solution using precaching. Cheers - Miles – daffinm Sep 16 '19 at 12:00
  • I spoke too soon @JeffPosnick. Could you take a look at [my demo app](https://github.com/daffinm/audio-cache-test) and let me know what I am doing wrong? – daffinm Sep 16 '19 at 17:55
  • I've updated the example with details on how to read from the precache. – Jeff Posnick Sep 16 '19 at 19:44
  • 1
    Thanks Jeff. I imagined something like that was going to be it but had no idea how to configure it. It works offline with both my real app and the demo/test app. Many thanks. – daffinm Sep 16 '19 at 22:22
  • Hi @Jeff Posnick. All was well until I deployed the app to firebase for beta testing. Now, when the service worker is enabled, I see the an error when I attempt to access one of the mp3 files. (I see no such error when the service worker is bypassed.) CacheOnly.mjs:115 Uncaught (in promise) no-response: The strategy could not generate a response for 'https://.firebaseapp.com/audio/Suicidal_Thoughts.mp3'. at CacheOnly.makeRequest (https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-strategies.dev.js:343:15) – daffinm Sep 27 '19 at 15:32
  • See [this question](https://stackoverflow.com/questions/58270383/workbox-pre-cached-audio-with-range-requests-router-fails-to-play-in-chrome-when) for a final resolution to this thread. – daffinm Oct 14 '19 at 22:30
  • thanks for help! Is it possible to configure it to cache audio from CDN? I've tried and it doesn't cache entire file just a part of content; CDN - placed on subdomain – Alex Golovin Dec 18 '19 at 00:07