59naga/mock-audio-element

View on GitHub
src/index.js

Summary

Maintainability
A
1 hr
Test Coverage
// Dependencies
import EventTarget from './event-target'

import musicMetaData from 'musicmetadata'
import request from 'request'

// Public
class Audio extends EventTarget{
  constructor(url){
    super()

    // similar loadstart OSX Google Chrome 46
    // see also http://www.w3schools.com/tags/ref_av_dom.asp
    // ... and test/index.html
    this.src= url || ''
    this.loop= false
    this.autoplay= false

    this.paused= true
    this.ended= false
    this.error= null

    this.currentTime= 0
    this.duration= NaN

    setTimeout(()=>{
      if(this.src){
        this.load()
      }
    })
  }
  load(){
    if(this._loadstart){
      return
    }
    if(this.duration>0){
      return
    }
    if(!this.src.length){
      return
    }

    this._loadstart= true

    request(this.src,{encoding:null},(error,response,buffer)=>{
      if(error){
        this.error= error
        return this.emit('error',error)
      }

      musicMetaData(request(this.src),{duration:true,fileSize:buffer.length},(error,meta)=>{
        if(error){
          this.error= error
          return this.emit('error',error)
        }

        this.duration= meta.duration

        if(this.autoplay){
          this._play()
        }

        this.emit('canplaythrough')
      })
    })
  }
  play(){
    if(isNaN(this.duration)){
      this.autoplay= true
      return this.load()
    }

    this._play()
  }
  _play(){
    this.paused= false
    this._previous= Date.now()

    this._pause()
    this._timeupdateId= setInterval(::this._timeupdate,100)

    this.emit('play')
  }
  pause(){
    this.paused= true
    this.autoplay= false
    this._pause()

    this.emit('pause')
  }
  _pause(){
    clearInterval(this._timeupdateId)
  }

  _timeupdate(){
    let diff= Date.now() - this._previous
    this._previous= Date.now()
    this.currentTime+= diff/1000
    if(this.currentTime>=this.duration){
      this.currentTime= this.duration
    }
    this.emit('timeupdate')

    if(this.currentTime===this.duration){
      if(this.loop){
        this.currentTime= 0
        return
      }
      this.pause()
      this.emit('ended')
    }
  }
}

export default Audio