progressive-web-appsjplayerworkbox

Cannot scrub/scroll through jPlayer audio when mp3 is cached by Workbox


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.


Solution

  • 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:

    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([...]);