File: //home/arjun/projects/buyercall/node_modules/vue-audio-visual/src/components/AvBase.js
import * as vue from 'vue'
/**
* Mixin component with base and common properties and functions.
*/
/**
* Base properties common for the audio-visual components
*/
const props = {
/**
* prop: 'audio-src'
* Audio element src attribute. When provided creates audio element
*/
audioSrc: {
type: String,
default: null
},
/**
* prop: 'audio-sink-device-id'
* Audio sink device id. When provided sets audio output device.
*/
audioSinkDeviceId: {
type: String,
default: null
},
/**
* prop: 'ref-link'
* Refrence to Audio element. When provided, then local audio element
* is not created and use refrence to the element. Component will
* search only for its parent refs.
*/
refLink: {
type: String,
default: null
},
/**
* prop: 'audio-controls'
* Audio element controls attribute. When provided should
* display audio element with controls
*/
audioControls: {
type: Boolean,
default: true
},
/**
* prop: 'cors-anonym'
* CORS requests for this element will not have the credentials flag set.
* Set crossOrigin property of audio element to 'anonymous'.
* Default: null
*/
corsAnonym: {
type: Boolean,
default: false
},
/**
* prop: 'audio-class'
* Audio element css class name.
*/
audioClass: {
type: String,
default: null
},
/**
* prop: 'canv-width'
* Canvas element width. Default 300
*/
canvWidth: {
type: Number,
default: 300
},
/**
* prop: 'canv-height'
* Canvas element height. Default 80
*/
canvHeight: {
type: Number,
default: 80
},
/**
* prop: 'canv-class'
* Canvas element css class name.
*/
canvClass: {
type: String,
default: null
},
/**
* prop: 'canv-top'
* Canvas element position on top relatively to audio element.
* Default: false
*/
canvTop: {
type: Boolean,
default: false
},
/**
* prop: 'canv-fill-color'
* Canvas fill background color. Can be string RGB color or canvas gradients array.
* Default is transperent.
*/
canvFillColor: {
type: [String, Array],
default: null
}
}
const methods = {
/**
* Create audio and canvas elements and insert in the HTML template.
* Using document.createElement to avoid Vue virtual DOM re-rendering
* which can lead to infinit loops.
*/
createHTMLElements: function () {
const canv = document.createElement('canvas')
const canvDiv = document.createElement('div')
let audioDiv = null
let audio = null
if (this.refLink) {
audio = this.$parent.$refs[this.refLink]
} else {
audio = document.createElement('audio')
audioDiv = document.createElement('div')
audio.setAttribute('src', this.audioSrc)
if (this.audioControls) audio.setAttribute('controls', true)
if (this.audioClass) audio.setAttribute('class', this.audioClass)
if (this.corsAnonym) audio.crossOrigin = 'anonymous'
audioDiv.appendChild(audio)
this.$el.appendChild(audioDiv)
}
if (this.canvClass) canv.setAttribute('class', this.canvClass)
if (this.canvWidth) canv.setAttribute('width', this.canvWidth)
if (this.canvHeight) canv.setAttribute('height', this.canvHeight)
canvDiv.appendChild(canv)
if (this.canvTop) {
this.$el.insertBefore(canvDiv, audioDiv)
} else {
this.$el.appendChild(canvDiv)
}
this.ctxWrapper = canv
this.ctx = canv.getContext('2d')
this.audio = audio
this.audio.load()
},
/**
* Set audio context analyser.
*/
async setAnalyser () {
this.audioCtx = this.audioCtx || new AudioContext()
this.analyser = this.analyser || this.audioCtx.createAnalyser()
const src = this.audioCtx.createMediaElementSource(this.audio)
const destination = this.audioCtx.createMediaStreamDestination()
src.connect(this.analyser)
this.analyser.fftSize = this.fftSize
this.analyser.connect(destination)
const audio = new Audio()
audio.srcObject = destination.stream
if (this.audioSinkDeviceId) {
await audio.setSinkId(this.audioSinkDeviceId)
}
audio.play()
},
/**
* Canvas gradient. Vertical, from top down
*/
fillGradient: function (colorsArray) {
const w = this.canvWidth
const h = this.canvHeight
const gradient = this.ctx.createLinearGradient(w / 2, 0, w / 2, h)
let offset = 0
colorsArray.forEach(color => {
gradient.addColorStop(offset, color)
offset += (1 / colorsArray.length)
})
return gradient
},
/**
* Return the inner audio element.
*/
getAudioElement: function () {
return this.audio
}
}
// A fix for webpack warnings across vue2 & vue3
const h = vue['h'[0]]
export default {
props,
expose: [
'getAudioElement'
],
render (hv2) {
if (h) {
// Vue3 render
return h('div')
}
// Vue2 render
return hv2('div')
},
mounted () {
this.createHTMLElements()
this.audio.onclick = () => {
if (!this.audioCtx) this.setAnalyser()
}
this.audio.onplay = () => {
this.$emit('playing')
if (!this.audioCtx) this.setAnalyser()
this.mainLoop()
if (this.audioCtx) { // not defined for waveform
this.audioCtx.resume()
}
}
this.audio.onpause = () => {
this.$emit('paused')
if (this.audioCtx) {
this.audioCtx.suspend()
cancelAnimationFrame(this.animId)
}
}
this.audio.onended = () => {
this.$emit('ended')
}
},
beforeDestroy () {
if (this.audioCtx) {
this.audioCtx.suspend()
}
cancelAnimationFrame(this.animId)
},
methods
}