Skip to content

Instantly share code, notes, and snippets.

@devongovett
Created December 12, 2011 16:05
Show Gist options
  • Save devongovett/1468024 to your computer and use it in GitHub Desktop.
Save devongovett/1468024 to your computer and use it in GitHub Desktop.
Aurora.js Ideas

Ideas for Aurora.js

Aurora.js is a JavaScript/CoffeeScript media framework that makes implementing audio formats, both containers and codecs much easier. Here are a few things it has:

  1. Sources (HTTP, streaming, File API, etc.)
  2. Shared Code (buffers, queues, bitstreams, etc.)
  3. Containers (demuxers)
  4. Codecs (decoders)
  5. Sink.js

Here is how one ought to be able to play a file:

player = Player.fromURL(“test.caf”);
player.play();

or:

player = Player.fromFile(file);
player.play();

First the player creates a source, HTTP or otherwise. All sources implement this common interface:

class Source extends EventEmitter
    constructor: (input...)
    start:
        emit ‘data’, chunk
        emit ‘error’, ...
        emit ‘end’
    pause:
    reset:
    seek: (offset)

Most classes extend the EventEmitter class, which handles common event emitting tasks and connects the pieces together. The framework creates the source, passing in some input. In the case of HTTP, this would be the URL to the audio file. Then it calls the start method, which at some point in the future emits a number of events, the most important of which being the data event.

Once the first chunk is emitted by the source, the player must find the proper demuxer for the format. Each registered demuxer's probe method is called and when one returns true, an instance is created. Here is the interface each demuxer must implement:

class SomeDemuxer extends Demuxer
    Demuxer.register(SomeDemuxer)

    @probe: (buffer)
        return true or false
    
    readChunk: (chunk)
        emit ‘format’, ...
        emit ‘cookie’, ...
        emit ‘metadata’, ...
        emit ‘data’, chunk
        emit ‘error’, ...
    
    seek: (timestamp)
    return byte position

The readChunk method is called by the framework whenever data is received from the source and is responsible for emitting a number of different events. The format event contains the general information about the audio format including the following fields:

  1. formatID
  2. sampleRate
  3. bytesPerPacket
  4. framesPerPacket
  5. channelsPerFrame
  6. bitsPerChannel

When this event is received, the player creates the proper decoder based on the formatID field. The cookie and data events are forwarded to the decoder, and any metadata contained in the file (title, artist, album art, etc.) should be collected and emitted as a single metadata event.

Here is the interface for all decoders:

class SomeDecoder extends Decoder
    setCookie: (cookie)
    readChunk:
        emit ‘data’, chunk
        emit ‘error’, ...
    
    seek: (position)

If one wants to write a new decoder using Aurora.js, they must only implement those three methods: the rest is taken care of by the framework. The constructor is implemented by the Decoder superclass. The setCookie method is called with the cookie if there is one when it is received from the demuxer, and the readChunk method is called when the framework is ready to receive the next decoded chunk.

Finally, the Player interface at the top of this, and what users interact with, looks like this:

class Player extends EventEmitter
    @fromFile: (file)
    @fromURL: (url)
    preload:
    play: 
    pause: 
    seek: (timestamp)
    property currentTime
    property duration
    property volume
    property metadata
    property buffered
    event ‘progress’
    event ‘buffer’
    event ‘ready’

Anyway, those are my ideas. I've actually implemented most of them already as well. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment