Source: MPD.js

class MPD {
  /**
   * 
   * @param {object} config - configuration object for the manifest
   */
  constructor (config = {
    mediaUrl: '',
    startNumber: 1,
    startTime: 0,
    timeOffset:  0,
    periodId: 1,
    minimumUpdatePeriod: 'PT60S',
    type: 'dynamic',
    profiles: 'urn:mpeg:dash:profile:isoff-live:2011',
    minBufferTime:  'PT12S',
    mimetype: 'video/webm'
  }) {
    this.doc = document.implementation.createDocument(null, 'mpd')
    this.mpd = null
    this.config = config
    this.serializer = new XMLSerializer()
  }

  /**
   * 
   * @param {Buffer} videoData - initial video data for the stream, must be less than 100kb 
   */
  *createMpd (videoData) {
    while (true) {
      this.mpd = this.doc.createElement('MPD')
      const date = new Date(Date.now()).toISOString()
      this.mpd.setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
      this.mpd.setAttribute('xmlns', 'urn:mpeg:dash:schema:mpd:2011')
      this.mpd.setAttribute('xsi:schemaLocation', 'urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd')
      this.mpd.setAttribute('type', this.config.type)
      this.mpd.setAttribute('profiles', this.config.profiles)
      this.mpd.setAttribute('minimumUpdatePeriod', this.config.minimumUpdatePeriod)
      this.mpd.setAttribute('minBufferTime', this.config.minBufferTime)
      this.mpd.setAttribute('availabilityStartTime', date)
      // create generators
      const periodGenerator = this.createPeriod(this.config.startNumber)
      const adaptationSetGenerator = this.createAdaptationSet(this.config.mimetype)
      const contentComponentGenerator = this.createContentComponent('video', this.config.startNumber)
      const segmentTemplateGenerator = this.createSegmentTemplate(videoData, "1000", "2000", 1,  this.config.mediaUrl)

      // generate elements
      const period = periodGenerator.next().value
      const adaptationSet = adaptationSetGenerator.next().value
      const contentComponent = contentComponentGenerator.next().value
      const segmentTemplate = segmentTemplateGenerator.next().value

      // append elements
      adaptationSet.appendChild(contentComponent)
      adaptationSet.appendChild(segmentTemplate)
      period.appendChild(adaptationSet)
      this.mpd.appendChild(period)
      this.config.startNumber++
      yield this.mpd
    }
  }

  /**
   * 
   * @param {integer} id - the id of the period
   */
  *createPeriod(id) {
    const period = this.doc.createElement('Period')
    while (true) {
     period.setAttribute('start', `PT${this.config.startTime + this.config.timeOffset}S`)
     period.setAttribute('id', id);  
     console.log('ID:::', id)
     yield period;
    }
  }

  /**
   * 
   * @param {string} mimetype - The MIME type of the stream
   * @returns a yielded mimeType attribute
   */
  *createAdaptationSet(mimetype = 'video/webm') {
    const as = this.doc.createElement('AdaptationSet')
    as.setAttribute('mimeType', mimetype)
    while(true) {
      yield as;
    }
  }

  /**
   * 
   * @param {string} contentType - The content type of the media being streams
   * @param {integer} id - The id of the content component
   */
  *createContentComponent(contentType = 'video', id = 1) {
    const cc = this.doc.createElement('ContentComponent');
    cc.setAttribute('contentType', contentType);
    while(true) {
      console.log(id)
      cc.setAttribute('id', id);
      id++;
      yield cc;
      
    }
  }

  /**
   * 
   * @param {Buffer} videoData - videoData to be streamed for initialization
   * @param {integer} timescale - The timescale of the media in microseconds
   * @param {integer} duration - The duration of the media in microseconds
   * @param {integer} startNumber - The start number of the media content
   * @param {string} media - The media URL for update PUTs
   */
  *createSegmentTemplate (videoData, timescale = 1000, duration = 2000, startNumber = 1,  media = '') {
    const st = this.doc.createElement('SegmentTemplate')
    st.setAttribute('startNumber', startNumber)
    st.setAttribute('duration', duration)
    st.setAttribute('timescale', timescale)
    st.setAttribute('media', media)
    while (true) {  
      st.setAttribute('initialization', "data:video/webm;base64," + btoa(videoData))
      yield st;
    }
  }

  /**
   * 
   * @returns {string} str - XML string representation of the manifest
   */
  getXMLString() {
    const str = this.serializer.serializeToString(this.mpd)
    return str
  }

  /**
   * 
   * @returns {File} file - A new File named init.mpd which contains the manifest XML
   */
  getXMLFile() {
    const file = new File([this.getXMLString()], 'init.mpd', {
      type: 'text/xml'
    })
    return file
  }
}

export {
  MPD
}