Coder Social home page Coder Social logo

promised-media-source's Introduction

A modern MediaSource API based on promises.

This library aims to provide an experimental playground for what a promise based MediaSource API could look like. It's a polyfill based on the current MSE API.

The modernized API removes events, rarely used features, and largely does away with exceptions thrown from methods. Everything that depends on some event having occurred is turned into a promise.

The intent is to be pretty radical at first and pare it down to a practical API, so at this time more may have been removed than is practical.

The new IDL looks like this:

interface MediaSource2 {
    constructor();

    Promise<SourceBuffer> addSourceBuffer(DOMString type);
    Promise<void> removeSourceBuffer(SourceBuffer buffer);
    Promise<void> endOfStream(optional EndOfStreamError error);
    Promise<void> setDuration(unrestricted double duration);

    [RaisesException] void setLiveSeekableRange(double start, double end);
    [RaisesException] void clearLiveSeekableRange();

    readonly attribute unrestricted double duration;

    static boolean isTypeSupported(DOMString type);
    static readonly attribute boolean canConstructInDedicatedWorker;
};

interface SourceBuffer {
    [RaisesException=Getter] readonly attribute TimeRanges buffered;
    readonly attribute AudioTrackList audioTracks;
    readonly attribute VideoTrackList videoTracks;

    Promise<void> appendBuffer(SharedBufferSource data);
    Promise<void> remove(double start, unrestricted double end);
    Promise<void> changeType(DOMString type);
    Promive<void> configure(SourceBufferOptions);

    [RaisesException] void abort();
};

dictionary SourceBufferOptions {
    AppendMode mode;
    double timestampOffset;
    double appendWindowStart;
    double appendWindowEnd;
};

These largely function as before except all promise based methods put a message into a queue for processing; messages are processed in order.

The biggest changes that aren't promise related:

  • abort() now purges the message queue in addition to resetting parser.
  • configure() replaces individual setters for things which control appendBuffer.
  • duration is now split into a readonly attribute and setter.

Using MediaSource for a simple case can look like this:

let mediaSource2 = new MediaSource2();

let sourceBufferReady = mediaSource2.addSourceBuffer(type);

let signalQuotaReady = null;

fetch(resource).then(response => response.body).then(async rs => {
  let sourceBuffer = await sourceBufferReady;

  const reader = stream.getReader();
  while (true) {
    const {done, value} = await reader.read();
    if (value && value.length > 0) {
      while (true) {
        try {
          await sourceBuffer.appendBuffer(value);
          break;
        } catch(e) {
          if (e.name === 'QuotaExceededError') {
            let quotaAvailable = new Promise((resolve, _) => {
              signalQuotaReady = resolve;
            });
            await quotaAvailable;
          } else {
            throw e;
          }
        };
      }
    }

    if (done) {
      mediaSource.endOfStream();
      return;
    }
  }
});

video.addEventListener('timeupdate', async _ => {
  let sourceBuffer = await sourceBufferReady;
  if (video.currentTime - sourceBuffer.buffered.start(0) > 2 * gcInterval) {
    sourceBuffer.remove(0, video.currentTime - gcInterval).then(_ => {
      if (signalQuotaReady !== null) {
        signalQuotaReady();
        signalQuotaReady = null;
      }
    });
  }
});

video.src = window.URL.createObjectURL(mediaSource2.mediaSource);

Open Questions

  • Has too much been removed?
    • SourceBufferLists are removed, clients must track manually.
    • No error event on SourceBuffers, only available throw promise rejection and the error event already on the HTMLMediaElement.
  • Is too much asynchronous now?
    • addSourceBuffer / removeSourceBuffer could be synchronous if some sort of class level Promise like MediaSource2.ready was added.
    • configure() offers no getters for the timestamp offset or append window, which may be needed in some cases?

promised-media-source's People

Contributors

dalecurtis avatar

Stargazers

Brad Dougherty avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.