Initial commit
This commit is contained in:
285
components/experiments/AudioElement2.vue
Normal file
285
components/experiments/AudioElement2.vue
Normal file
@@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- Slot for passing any audio element -->
|
||||
<slot />
|
||||
<div class="slider">
|
||||
<input
|
||||
id="gain-control"
|
||||
v-model="volume"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.02"
|
||||
@wheel.prevent="changeVolumeOnWheel"
|
||||
>
|
||||
</div>
|
||||
<audio
|
||||
ref="audioElement"
|
||||
hidden
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
@play="handlePlay"
|
||||
@pause="handlePause"
|
||||
@keydown="handleKeyDown"
|
||||
@loadedmetadata="handleLoaded"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { useAudioStore } from '~/stores/audio'
|
||||
import { useUserStore } from '~/stores/user'
|
||||
|
||||
export default {
|
||||
name: 'AudioElement',
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Unknown'
|
||||
}
|
||||
},
|
||||
emits: ['update:volume', 'update:loaded', 'update:playing', 'update:fadeout'],
|
||||
setup (props, { emit }) {
|
||||
const audioStore = useAudioStore()
|
||||
const audioElement = ref<HTMLAudioElement | null>(null)
|
||||
const volume = ref(1)
|
||||
|
||||
const play = () => {
|
||||
try {
|
||||
// set audio element to mute, will be anyway muted after connecting to the web audio graph
|
||||
// useNuxtApp().$logger.log('Trigger Play of the audioelement tag: CurrentTime ' + currentTime + ' paused' + paused + ' ended' + ended)
|
||||
const sink = useUserStore().audioOutputDevice as MediaDeviceInfo
|
||||
audioElement.value?.setSinkId(sink.deviceId)
|
||||
audioElement.value?.play()
|
||||
if (audioElement.value) { audioElement.value.muted = true }
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
const pause = () => {
|
||||
audioElement.value?.pause()
|
||||
}
|
||||
|
||||
const pauseFadeOut = () => {
|
||||
// useNuxtApp().$logger.log('pauseFadeOut')
|
||||
emit('update:fadeout')
|
||||
setTimeout(() => {
|
||||
pause()
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
const isPlaying = () => {
|
||||
return audioStore.playing
|
||||
}
|
||||
|
||||
onUpdated(() => {
|
||||
if (props.title === 'Noise') {
|
||||
// useNuxtApp().$logger.log('cannot set control of noise to false')
|
||||
} else if ('mediaSession' in navigator) {
|
||||
const path = window.location.origin + '/images/scenery/' + props.title.toLowerCase() + '.jpg'
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: props.title,
|
||||
artist: 'mindboost',
|
||||
album: 'mindboost Originale',
|
||||
artwork: [
|
||||
{ src: path, sizes: '192x192', type: 'image/jpeg' }
|
||||
]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => audioStore.playing, (newValue) => {
|
||||
if (newValue) {
|
||||
// useNuxtApp().$logger.log('PLAY THE AUDIO')
|
||||
play()
|
||||
} else {
|
||||
// useNuxtApp().$logger.log('PAUSE THE AUDIO')
|
||||
pauseFadeOut()
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => volume.value, (newValue) => {
|
||||
if (audioElement.value) {
|
||||
emit('update:volume', newValue)
|
||||
}
|
||||
})
|
||||
|
||||
const changeVolumeOnWheel = (event:WheelEvent) => {
|
||||
// Adjust volume on wheel scroll
|
||||
const deltaY = event.deltaY
|
||||
if (deltaY < 0) {
|
||||
const volumeAdd = (Math.min(1, volume.value + 0.02))
|
||||
volume.value = volumeAdd
|
||||
} else {
|
||||
const volumeCut = (Math.max(0, volume.value - 0.02))
|
||||
volume.value = volumeCut
|
||||
}
|
||||
}
|
||||
|
||||
let enableKeyHandler = true
|
||||
|
||||
const debounce = <T extends (...args: any[]) => void>(func: T, timeout: number = 1500): () => void => {
|
||||
let timer: NodeJS.Timeout | null
|
||||
return () => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
timer = setTimeout(() => { func.apply(this) }, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
const reEnableKeyHandler = debounce(() => {
|
||||
enableKeyHandler = true
|
||||
})
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (!enableKeyHandler) { return }
|
||||
if (e.code === 'Space') {
|
||||
e.preventDefault() // Prevent the default action (scrolling)
|
||||
// useNuxtApp().$logger.log('The current state is ' + audioStore.playing + ' so start or stop audio')
|
||||
if (audioStore.playing) {
|
||||
handlePause()
|
||||
} else {
|
||||
handlePlay()
|
||||
}
|
||||
enableKeyHandler = false // Disable handler
|
||||
reEnableKeyHandler()
|
||||
}
|
||||
}
|
||||
|
||||
const handlePlay = () => {
|
||||
// useNuxtApp().$logger.log('handlePlay called ' + audioStore.isPlaying())
|
||||
// First handlePlay is triggered by the autoplay, so no need to start play
|
||||
emit('update:playing', true)
|
||||
audioStore.setPlaying(true)
|
||||
// useNuxtApp().$logger.log('handlePlay ended with ' + audioStore.isPlaying())
|
||||
}
|
||||
|
||||
const handlePause = () => {
|
||||
// useNuxtApp().$logger.log('handlePause: Change play state to false')
|
||||
emit('update:playing', false)
|
||||
audioStore.playing = false
|
||||
}
|
||||
|
||||
const handleLoaded = () => {
|
||||
emit('update:loaded', true)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (audioElement.value) {
|
||||
audioElement.value.src = props.src
|
||||
if (props.title !== 'Noise') {
|
||||
window.addEventListener('keydown', handleKeyDown.bind(this))
|
||||
if ('mediaSession' in navigator) {
|
||||
// Play action
|
||||
navigator.mediaSession.setActionHandler('play', (_e) => {
|
||||
handlePlay()
|
||||
// if (!enableMediaHandler) {
|
||||
/// / useNuxtApp().$logger.log('during event handling - being busy ')
|
||||
// return
|
||||
// }
|
||||
// enableMediaHandler = false // Disable handler
|
||||
// reEnableMediaHandler()
|
||||
// // Your play action here
|
||||
})
|
||||
|
||||
// Stop action
|
||||
navigator.mediaSession.setActionHandler('stop', (_e) => {
|
||||
// if (!enableMediaHandler) { return }
|
||||
// // Your stop action here
|
||||
// if (audioElement.value) {
|
||||
// audioElement.value.currentTime = 0
|
||||
// audioElement.value.src = ''
|
||||
// audioElement.value.removeAttribute('src')
|
||||
// }
|
||||
// audioStore.playing = false
|
||||
})
|
||||
|
||||
// Pause action
|
||||
navigator.mediaSession.setActionHandler('pause', (_e) => {
|
||||
handlePause()
|
||||
// if (!enableMediaHandler) {
|
||||
/// / useNuxtApp().$logger.log('during event handling - being busy ')
|
||||
// return
|
||||
// }
|
||||
// audioStore.playing = false
|
||||
// enableMediaHandler = false // Disable handler
|
||||
// reEnableMediaHandler()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
onRenderTriggered(() => {
|
||||
// useNuxtApp().$logger.log('render AudioElement-----------' + props.title)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keydown', handleKeyDown.bind(this))
|
||||
})
|
||||
|
||||
return {
|
||||
audioElement,
|
||||
play,
|
||||
pause,
|
||||
isPlaying,
|
||||
handlePlay,
|
||||
handlePause,
|
||||
handleLoaded,
|
||||
handleKeyDown,
|
||||
volume,
|
||||
changeVolumeOnWheel
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.slider {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
/* Style adjustments if needed */
|
||||
input[type="range"] {
|
||||
background:transparent !important;
|
||||
}
|
||||
/* Styles the track */
|
||||
input[type="range"]::-webkit-slider-runnable-track {
|
||||
background: #e9c046; /* yellow track */
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-track {
|
||||
background: #e9c046; /* yellow track */
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
input[type="range"]::-ms-track {
|
||||
background: #e9c046; /* yellow track */
|
||||
border-color: transparent;
|
||||
color: transparent;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
/* Styles the thumb */
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none; /* Required to style in Webkit browsers */
|
||||
margin-top: -6px; /* Adjusts the position of the thumb relative to the track */
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-thumb {
|
||||
border: none; /* Removes any default border */
|
||||
}
|
||||
|
||||
input[type="range"]::-ms-thumb {
|
||||
margin-top: 0; /* May need to adjust the position similar to webkit */
|
||||
border: none; /* Removes any default border */
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user