More WebDJ work.

This commit is contained in:
Buster Neece 2022-12-31 17:11:24 -06:00
parent b498288965
commit 901faaee50
No known key found for this signature in database
GPG Key ID: F1D2E64A0005E80E
12 changed files with 82 additions and 64 deletions

View File

@ -1,2 +1 @@
vue/vendor/chartjs-colorschemes/*
vue/vendor/webcast/*

View File

@ -60,6 +60,12 @@ const jsFiles = {
files: [
'node_modules/luxon/build/global/luxon.min.js'
]
},
'webcaster': {
base: null,
files: [
'js/webcaster/*.js'
]
}
};

View File

@ -44,7 +44,6 @@ import SettingsPanel from './WebDJ/SettingsPanel.vue';
import {useWebDjNode} from "~/components/Public/WebDJ/useWebDjNode";
import {provide} from "vue";
import {useWebcaster, webcasterProps} from "~/components/Public/WebDJ/useWebcaster";
import '~/vendor/webcast/taglib';
const props = defineProps({
...webcasterProps,

View File

@ -84,9 +84,9 @@ import {useDevicesList} from "@vueuse/core";
import {ref, watch} from "vue";
import {useWebDjTrack} from "~/components/Public/WebDJ/useWebDjTrack";
const {node, isPlaying, trackGain, trackPassThrough, volume, prepare, stop} = useWebDjTrack();
const {node, source, isPlaying, trackGain, trackPassThrough, volume, prepare, stop} = useWebDjTrack();
const {context, createMicrophoneSource} = node;
const {createMicrophoneSource} = node;
const {audioInputs} = useDevicesList({
requestPermissions: true,
@ -94,28 +94,30 @@ const {audioInputs} = useDevicesList({
const device = ref(audioInputs.value[0]?.deviceId);
let source = null;
let destination = null;
const createSource = () => {
if (source != null) {
source.disconnect(context.destination);
if (source.value != null && destination !== null) {
source.value.disconnect(destination);
}
createMicrophoneSource(device.value, (newSource) => {
source = newSource;
source.connect(context.destination);
source.value = newSource;
if (destination !== null) {
newSource.connect(destination);
}
});
};
watch(device, () => {
if (this.source == null) {
if (source.value == null) {
return;
}
createSource();
});
const play = () => {
prepare();
destination = prepare();
createSource();
}

View File

@ -187,6 +187,7 @@ const isLeftPlaylist = computed(() => {
const {
node,
source,
isPlaying,
isPaused,
trackGain,
@ -198,7 +199,7 @@ const {
stop
} = useWebDjTrack();
const {context, createFileSource, updateMetadata} = node;
const {createFileSource, sendMetadata} = node;
const fileIndex = ref(-1);
const files = ref([]);
@ -210,8 +211,8 @@ const {$gettext} = useTranslate();
const langHeader = computed(() => {
return isLeftPlaylist.value
? this.$gettext('Playlist 1')
: this.$gettext('Playlist 2');
? $gettext('Playlist 1')
: $gettext('Playlist 2');
});
const addNewFiles = (newFiles) => {
@ -226,8 +227,6 @@ const addNewFiles = (newFiles) => {
});
};
let source = null;
const selectFile = (options = {}) => {
if (files.value.length === 0) {
return;
@ -271,23 +270,23 @@ const play = (options = {}) => {
stop();
prepare();
let destination = prepare();
createFileSource(file, (newSource) => {
source = newSource;
source.connect(context.destination);
source.value = newSource;
newSource.connect(destination);
if (source.duration !== null) {
duration.value = source.duration();
if (newSource.duration !== null) {
duration.value = newSource.duration();
} else if (file.audio !== null) {
duration.value = parseFloat(this.file.audio.length);
duration.value = parseFloat(file.audio.length);
}
source.play(file);
newSource.play(file);
updateMetadata({
title: this.file.metadata.title,
artist: this.file.metadata.artist
sendMetadata({
title: file.metadata.title,
artist: file.metadata.artist
});
}, () => {
stop();

View File

@ -146,6 +146,7 @@
<script setup>
import {computed, inject, ref} from "vue";
import {syncRef} from "@vueuse/core";
import {useTranslate} from "~/vendor/gettext";
const props = defineProps({
stationName: {
@ -166,10 +167,12 @@ const {
sendMetadata
} = inject('node');
const {$gettext} = useTranslate();
const langStreamButton = computed(() => {
return (isStreaming.value)
? this.$gettext('Stop Streaming')
: this.$gettext('Start Streaming');
? $gettext('Stop Streaming')
: $gettext('Start Streaming');
});
const shownMetadata = ref({});

View File

@ -11,16 +11,16 @@ export function useWebDjNode(webcaster) {
const sink = context.createScriptProcessor(256, 2, 2);
sink.onaudioprocess((buf) => {
sink.onaudioprocess = (buf) => {
for (let channel = 0; channel < buf.inputBuffer.numberOfChannels - 1; channel++) {
let channelData = buf.inputBuffer.getChannelData(channel);
buf.outputBuffer.getChannelData(channel).set(channelData);
}
});
};
const passThrough = context.createScriptProcessor(256, 2, 2);
passThrough.onaudioprocess((buf) => {
passThrough.onaudioprocess = (buf) => {
for (let channel = 0; channel < buf.inputBuffer.numberOfChannels - 1; channel++) {
let channelData = buf.inputBuffer.getChannelData(channel);
@ -30,7 +30,7 @@ export function useWebDjNode(webcaster) {
buf.outputBuffer.getChannelData(channel).set(new Float32Array(channelData.length));
}
}
});
};
sink.connect(passThrough);
passThrough.connect(context.destination);
@ -105,8 +105,8 @@ export function useWebDjNode(webcaster) {
});
};
const createFileSource = (file, cb) => {
return createAudioSource(file, cb);
const createFileSource = (file, cb, onEnd) => {
return createAudioSource(file, cb, onEnd);
};
const createMicrophoneSource = (audioDeviceId, cb) => {

View File

@ -1,4 +1,4 @@
import {computed, inject, ref, watch} from "vue";
import {computed, inject, ref, shallowRef, watch} from "vue";
export function useWebDjTrack() {
const node = inject('node');
@ -8,17 +8,7 @@ export function useWebDjTrack() {
const position = ref(null);
const volume = ref(0);
let source = null;
const isPlaying = computed(() => {
return source !== null;
});
const isPaused = computed(() => {
return (source !== null)
? source.paused
: false;
});
let source = shallowRef(null);
const createControlsNode = () => {
const bufferSize = 4096;
@ -27,8 +17,8 @@ export function useWebDjTrack() {
let newSource = node.context.createScriptProcessor(bufferSize, 2, 2);
newSource.onaudioprocess((buf) => {
position.value = source?.position();
newSource.onaudioprocess = (buf) => {
position.value = source.value?.position();
for (let channel = 0; channel < buf.inputBuffer.numberOfChannels; channel++) {
let channelData = buf.inputBuffer.getChannelData(channel);
@ -42,7 +32,7 @@ export function useWebDjTrack() {
buf.outputBuffer.getChannelData(channel).set(channelData);
}
});
};
return newSource;
};
@ -50,7 +40,7 @@ export function useWebDjTrack() {
const createPassThrough = () => {
let newSource = node.context.createScriptProcessor(256, 2, 2);
newSource.onaudioprocess((buf) => {
newSource.onaudioprocess = (buf) => {
for (let channel = 0; channel < buf.inputBuffer.numberOfChannels; channel++) {
let channelData = buf.inputBuffer.getChannelData(channel);
@ -60,7 +50,7 @@ export function useWebDjTrack() {
buf.outputBuffer.getChannelData(channel).set(new Float32Array(channelData.length));
}
}
});
};
return newSource;
};
@ -90,35 +80,48 @@ export function useWebDjTrack() {
trackGainNode.connect(passThroughNode);
node.context.resume();
return trackGainNode;
}
const isPlaying = computed(() => {
return source.value !== null;
});
const isPaused = computed(() => {
return (source.value !== null)
? source.value.paused
: false;
});
const togglePause = () => {
if (source === null) {
if (source.value === null) {
return;
}
if (source.paused) {
source.play();
if (source.value.paused) {
source.value.play();
} else {
source.pause();
source.value.pause();
}
};
const stop = () => {
source?.stop();
source?.disconnect();
source.value?.stop();
source.value?.disconnect();
trackGainNode?.disconnect();
controlsNode?.disconnect();
passThroughNode?.disconnect();
source = trackGainNode = controlsNode = passThroughNode = null;
source.value = trackGainNode = controlsNode = passThroughNode = null;
position.value = 0.0;
};
return {
node,
source,
trackGain,
trackPassThrough,
position,

View File

@ -24,7 +24,7 @@ export function useWebcaster(props) {
};
if (null !== username) {
hello.username = username;
hello.user = username;
}
if (null !== password) {
hello.password = password;
@ -52,10 +52,12 @@ export function useWebcaster(props) {
};
const sendMetadata = (data) => {
socket.send(JSON.stringify({
type: "metadata",
data,
}));
if (isConnected()) {
socket.send(JSON.stringify({
type: "metadata",
data,
}));
}
}
return {

View File

@ -39,7 +39,6 @@ final class WebDjAction
}
$wss_url = (string)$backend->getWebStreamingUrl($station, $request->getRouter()->getBaseUrl());
$wss_url = str_replace('wss://', '', $wss_url);
return $request->getView()->renderToResponse(
response: $response->withHeader('X-Frame-Options', '*'),

View File

@ -15,6 +15,12 @@ $this->layout(
]
);
$sections->appendStart('bodyjs');
?>
<script src="<?= $this->assetUrl('dist/lib/webcaster/taglib.js') ?>"></script>
<?php
$sections->end();
echo $this->fetch(
'partials/vue_body',
[