AzuraCast/frontend/vue/components/Public/WebDJ/useWebDjNode.js

149 lines
3.9 KiB
JavaScript

import {inject, provide, ref} from "vue";
const injectKey = "webDjNode";
export function useInjectWebDjNode() {
return inject(injectKey);
}
export function useProvideWebDjNode(node) {
provide(injectKey, node);
}
export function useWebDjNode(webcaster) {
const {isConnected, connect: connectSocket, metadata, sendMetadata} = webcaster;
const doPassThrough = ref(false);
const context = new AudioContext({
sampleRate: 44100
});
const sink = context.createScriptProcessor(256, 2, 2);
sink.onaudioprocess = (buf) => {
for (let channel = 0; channel < buf.inputBuffer.numberOfChannels; channel++) {
let channelData = buf.inputBuffer.getChannelData(channel);
buf.outputBuffer.getChannelData(channel).set(channelData);
}
};
const passThrough = context.createScriptProcessor(256, 2, 2);
passThrough.onaudioprocess = (buf) => {
for (let channel = 0; channel < buf.inputBuffer.numberOfChannels; channel++) {
let channelData = buf.inputBuffer.getChannelData(channel);
if (doPassThrough.value) {
buf.outputBuffer.getChannelData(channel).set(channelData);
} else {
buf.outputBuffer.getChannelData(channel).set(new Float32Array(channelData.length));
}
}
};
sink.connect(passThrough);
passThrough.connect(context.destination);
const streamNode = context.createMediaStreamDestination();
streamNode.channelCount = 2;
sink.connect(streamNode);
let mediaRecorder;
const startStream = (username = null, password = null) => {
context.resume();
mediaRecorder = new MediaRecorder(
streamNode.stream,
{
mimeType: "audio/webm;codecs=opus",
audioBitsPerSecond: 128 * 1000
}
);
connectSocket(mediaRecorder, username, password);
mediaRecorder.start(1000);
}
const stopStream = () => {
mediaRecorder?.stop();
};
const createAudioSource = ({file, audio}, cb, onEnd) => {
const el = new Audio(URL.createObjectURL(file));
el.controls = false;
el.autoplay = false;
el.loop = false;
let source = null;
el.addEventListener("ended", () => {
if (typeof onEnd === "function") {
onEnd();
}
});
el.addEventListener("canplay", () => {
if (source) {
return;
}
source = context.createMediaElementSource(el);
source.play = () => el.play()
source.position = () => el.currentTime;
source.duration = () => el.duration;
source.paused = () => el.paused;
source.stop = () => {
el.pause();
return el.remove();
};
source.pause = () => el.pause;
source.seek = (percent) => {
let time = percent * parseFloat(audio.length);
el.currentTime = time;
return time;
};
return cb(source);
});
};
const createMicrophoneSource = (audioDeviceId, cb) => {
navigator.mediaDevices.getUserMedia({
video: false,
audio: {
deviceId: audioDeviceId
}
}).then((stream) => {
let source = context.createMediaStreamSource(stream);
source.stop = () => {
let ref = stream.getAudioTracks();
return (ref !== null)
? ref[0].stop()
: 0;
}
return cb(source);
});
};
return {
doPassThrough,
isConnected,
context,
sink,
passThrough,
streamNode,
startStream,
stopStream,
createAudioSource,
createMicrophoneSource,
metadata,
sendMetadata
};
}