Use blob URLs to avoid loading the audio data twice

This commit is contained in:
Marks Polakovs 2020-03-24 13:18:10 +01:00
parent 519f11e294
commit 1142a87f5c

View file

@ -14,7 +14,6 @@ import { AppThunk } from "../store";
import { RootState } from "../rootReducer";
import WaveSurfer from "wavesurfer.js";
console.log(Between);
const audioContext = new AudioContext();
@ -164,7 +163,10 @@ const mixerState = createSlice({
micOpen(state) {
state.mic.open = true;
},
setMicLevels(state, action: PayloadAction<{volume: number, gain: number}>) {
setMicLevels(
state,
action: PayloadAction<{ volume: number; gain: number }>
) {
state.mic.volume = action.payload.volume;
state.mic.gain = action.payload.gain;
},
@ -173,37 +175,50 @@ const mixerState = createSlice({
action: PayloadAction<{
player: number;
time: number;
}>) {
state.players[action.payload.player].timeCurrent = action.payload.time;
state.players[action.payload.player].timeRemaining = state.players[action.payload.player].timeLength - action.payload.time;
}>
) {
state.players[action.payload.player].timeCurrent =
action.payload.time;
state.players[action.payload.player].timeRemaining =
state.players[action.payload.player].timeLength -
action.payload.time;
},
setTimeLength(
state,
action: PayloadAction<{
player: number;
time: number;
}>) {
state.players[action.payload.player].timeLength = action.payload.time;
}>
) {
state.players[action.payload.player].timeLength =
action.payload.time;
},
setAutoAdvance(
state,
action: PayloadAction<{
player: number;
}>) {
state.players[action.payload.player].autoAdvance = !state.players[action.payload.player].autoAdvance;
}>
) {
state.players[action.payload.player].autoAdvance = !state.players[
action.payload.player
].autoAdvance;
},
setPlayOnLoad(
state,
action: PayloadAction<{
player: number;
}>) {
state.players[action.payload.player].playOnLoad = !state.players[action.payload.player].playOnLoad;
}>
) {
state.players[action.payload.player].playOnLoad = !state.players[
action.payload.player
].playOnLoad;
},
setRepeat(
state,
action: PayloadAction<{
player: number;
}>) {
}>
) {
var playVal = state.players[action.payload.player].repeat;
switch (playVal) {
case "none":
@ -218,16 +233,15 @@ const mixerState = createSlice({
}
state.players[action.payload.player].repeat = playVal;
}
}
});
export default mixerState.reducer;
export const load = (player: number, item: PlanItem | Track): AppThunk => (
dispatch,
getState
) => {
export const load = (
player: number,
item: PlanItem | Track
): AppThunk => async (dispatch, getState) => {
if (typeof playerSources[player] !== "undefined") {
if (!playerSources[player].mediaElement.paused) {
// already playing, don't kill playback
@ -235,18 +249,19 @@ export const load = (player: number, item: PlanItem | Track): AppThunk => (
}
}
dispatch(mixerState.actions.loadItem({ player, item }));
const el = new Audio();
el.crossOrigin = "use-credentials";
let url;
if ("album" in item) {
// track
el.src =
url =
MYRADIO_NON_API_BASE +
"/NIPSWeb/secure_play?recordid=" +
item.album.recordid +
"&trackid=" +
item.trackid;
} else if ("type" in item && item.type == "aux") {
el.src =
url =
MYRADIO_NON_API_BASE +
"/NIPSWeb/managed_play?managedid=" +
item.managedid;
@ -255,10 +270,19 @@ export const load = (player: number, item: PlanItem | Track): AppThunk => (
"Unsure how to handle this!\r\n\r\n" + JSON.stringify(item)
);
}
const result = await fetch(url, { credentials: "include" });
const rawData = await result.arrayBuffer();
const blob = new Blob([rawData]);
const blobUrl = URL.createObjectURL(blob);
const el = new Audio();
el.src = blobUrl;
el.crossOrigin = "use-credentials";
var wavesurfer = getState().mixer.players[player].wavesurfer;
var playerState = getState().mixer.players[player];
el.oncanplay = () => {
console.log("can play");
};
@ -279,15 +303,14 @@ export const load = (player: number, item: PlanItem | Track): AppThunk => (
playerSources[player] = sauce;
playerGains[player] = gain;
let waveform = document.getElementById("waveform-" + player.toString());
if (waveform != undefined) {
waveform.innerHTML = "";
}
wavesurfer = WaveSurfer.create({
container: '#waveform-' + player.toString(),
waveColor: '#CCCCFF',
progressColor: '#9999FF',
container: "#waveform-" + player.toString(),
waveColor: "#CCCCFF",
progressColor: "#9999FF",
backend: "MediaElement",
responsive: true
@ -297,13 +320,13 @@ export const load = (player: number, item: PlanItem | Track): AppThunk => (
//el.load();
if (wavesurfer != null) {
wavesurfer.params.xhr = {
cache: 'default',
mode: 'cors',
method: 'GET',
credentials: 'include',
cache: "default",
mode: "cors",
method: "GET",
credentials: "include",
withCredentials: true,
redirect: 'follow',
referrer: 'client',
redirect: "follow",
referrer: "client",
headers: [
{
key: "Access-Control-Allow-Credentials",
@ -311,19 +334,36 @@ export const load = (player: number, item: PlanItem | Track): AppThunk => (
}
]
};
dispatch(mixerState.actions.setTimeCurrent({ player: player, time: 0 }));
dispatch(
mixerState.actions.setTimeCurrent({ player: player, time: 0 })
);
dispatch(mixerState.actions.setTimeLength({ player: player, time: 0 }));
wavesurfer.load(playerSources[player].mediaElement);
wavesurfer.on('ready', function () {
wavesurfer.on("ready", function() {
if (wavesurfer) {
let duration = wavesurfer.getDuration();
dispatch(mixerState.actions.setTimeCurrent({ player: player, time: 0 }));
dispatch(mixerState.actions.setTimeLength({ player: player, time: duration }));
dispatch(
mixerState.actions.setTimeCurrent({
player: player,
time: 0
})
);
dispatch(
mixerState.actions.setTimeLength({
player: player,
time: duration
})
);
}
});
wavesurfer.on('audioprocess', function (time: number) {
if (wavesurfer && Math.random() > 0.90) {
dispatch(mixerState.actions.setTimeCurrent({ player: player, time: time}));
wavesurfer.on("audioprocess", function(time: number) {
if (wavesurfer && Math.random() > 0.9) {
dispatch(
mixerState.actions.setTimeCurrent({
player: player,
time: time
})
);
}
});
}
@ -383,21 +423,15 @@ export const stop = (player: number): AppThunk => dispatch => {
};
export const toggleAutoAdvance = (player: number): AppThunk => dispatch => {
dispatch(
mixerState.actions.setAutoAdvance({ player })
);
dispatch(mixerState.actions.setAutoAdvance({ player }));
};
export const togglePlayOnLoad = (player: number): AppThunk => dispatch => {
dispatch(
mixerState.actions.setPlayOnLoad({ player })
);
dispatch(mixerState.actions.setPlayOnLoad({ player }));
};
export const toggleRepeat = (player: number): AppThunk => dispatch => {
dispatch(
mixerState.actions.setRepeat({ player })
);
dispatch(mixerState.actions.setRepeat({ player }));
};
const FADE_TIME_SECONDS = 1;
@ -508,19 +542,26 @@ export const openMicrophone = (): AppThunk => async (dispatch, getState) => {
return;
}
// Okay, we have a mic stream, time to do some audio nonsense
micSource = audioContext.createMediaStreamSource(micMedia)
micSource = audioContext.createMediaStreamSource(micMedia);
micGain = audioContext.createGain();
micCompressor = audioContext.createDynamicsCompressor();
// TODO: for testing we're connecting mic output to main out
// When streaming works we don't want to do this, because the latency is high enough to speech-jam
micSource.connect(micGain).connect(micCompressor).connect(destination);
micSource
.connect(micGain)
.connect(micCompressor)
.connect(destination);
dispatch(mixerState.actions.micOpen());
};
export const setMicVolume = (level: MicVolumePresetEnum): AppThunk => dispatch => {
export const setMicVolume = (
level: MicVolumePresetEnum
): AppThunk => dispatch => {
// no tween fuckery here, just cut the level
const levelVal = level === "full" ? 1 : 0;
dispatch(mixerState.actions.setMicLevels({ volume: levelVal, gain: levelVal }));
dispatch(
mixerState.actions.setMicLevels({ volume: levelVal, gain: levelVal })
);
};
export const mixerMiddleware: Middleware<