This commit is contained in:
Marks Polakovs 2020-04-13 13:22:38 +02:00
parent 7be882acbd
commit c3b0f5675b
4 changed files with 757 additions and 730 deletions

View file

@ -240,6 +240,7 @@ class Session(object):
except MediaStreamError as e:
print(self.connection_id, e)
await self.end()
raise e
if self.running:
# Right, depending on the format, we may need to do some fuckery.
# Jack expects all audio to be 32 bit floating point

View file

@ -21,6 +21,7 @@ export class WebRTCStreamer extends Streamer {
}
async start(): Promise<void> {
console.log("RTCStreamer start");
this.pc = new RTCPeerConnection({
iceServers: [
{
@ -52,6 +53,7 @@ export class WebRTCStreamer extends Streamer {
};
this.stream.getAudioTracks().forEach(track => this.pc!.addTrack(track));
console.log("PC created");
this.ws = new WebSocket(process.env.REACT_APP_WS_URL!);
this.ws.onopen = e => {
console.log("WS open");
@ -62,6 +64,7 @@ export class WebRTCStreamer extends Streamer {
this.onStateChange(this.mapStateToConnectionState());
};
this.ws.addEventListener("message", this.onMessage.bind(this));
console.log("WS created");
}
async stop(): Promise<void> {

View file

@ -87,6 +87,16 @@ export const changeBroadcastSetting = <K extends keyof BroadcastState>(
};
export const registerTimeslot = (): AppThunk => async (dispatch, getState) => {
if (!getState().session.userCanBroadcast) {
dispatch(
NavbarState.showAlert({
color: "warning",
content: "You are not WebStudio Trained and cannot go live.",
closure: 7000
})
);
return;
}
if (getState().broadcast.stage === "NOT_REGISTERED") {
var state = getState().session;
const memberid = state.currentUser?.memberid;
@ -95,6 +105,7 @@ export const registerTimeslot = (): AppThunk => async (dispatch, getState) => {
var sourceid = getState().broadcast.sourceID;
try {
var connID = await sendBroadcastRegister(timeslotid, memberid, sourceid);
console.log(connID);
if (connID !== undefined) {
dispatch(broadcastState.actions.setConnID(connID["connid"]));
dispatch(startStreaming());
@ -227,19 +238,14 @@ export function sendTracklistStart(trackid: number): Promise<TrackListItem> {
}
export const startStreaming = (): AppThunk => async (dispatch, getState) => {
if (!getState().session.userCanBroadcast) {
dispatch(
NavbarState.showAlert({
color: "warning",
content: "You are not WebStudio Trained and cannot go live.",
closure: 7000
})
);
return;
}
console.log("starting streamer.");
streamer = new WebRTCStreamer(MixerState.destination.stream);
streamer.addConnectionStateListener(state => {
dispatch(broadcastState.actions.setConnectionState(state));
if (state === "CONNECTION_LOST") {
// un-register if we drop, let the user manually reconnect
dispatch(broadcastState.actions.setConnID(null));
}
});
await streamer.start();
};

View file

@ -13,7 +13,9 @@ import { Track, MYRADIO_NON_API_BASE, AuxItem } from "../api";
import { AppThunk } from "../store";
import { RootState } from "../rootReducer";
import WaveSurfer from "wavesurfer.js";
import { createLoudnessMeasurement } from "./loudness";
import NewsIntro from "../assets/audio/NewsIntro.wav";
import NewsEndCountdown from "../assets/audio/NewsEndCountdown.wav";
const audioContext = new AudioContext();
const wavesurfers: WaveSurfer[] = [];
@ -38,6 +40,32 @@ export const destination = audioContext.createMediaStreamDestination();
console.log("final destination", destination);
finalCompressor.connect(destination);
const newsEndCountdownEl = new Audio(NewsEndCountdown);
newsEndCountdownEl.preload = "auto";
newsEndCountdownEl.volume = 0.5;
const newsEndCountdownNode = audioContext.createMediaElementSource(
newsEndCountdownEl
);
newsEndCountdownNode.connect(audioContext.destination);
const newsStartCountdownEl = new Audio(NewsIntro);
newsStartCountdownEl.preload = "auto";
newsStartCountdownEl.volume = 0.5;
const newsStartCountdownNode = audioContext.createMediaElementSource(
newsStartCountdownEl
);
newsStartCountdownNode.connect(audioContext.destination);
export async function playNewsEnd() {
newsEndCountdownEl.currentTime = 0;
await newsEndCountdownEl.play();
}
export async function playNewsIntro() {
newsStartCountdownEl.currentTime = 0;
await newsStartCountdownEl.play();
}
type PlayerStateEnum = "playing" | "paused" | "stopped";
type PlayerRepeatEnum = "none" | "one" | "all";
type VolumePresetEnum = "off" | "bed" | "full";
@ -147,8 +175,7 @@ const mixerState = createSlice({
item: PlanItem | Track | AuxItem;
}>
) {
state.players[action.payload.player].loadedItem =
action.payload.item;
state.players[action.payload.player].loadedItem = action.payload.item;
state.players[action.payload.player].loading = 0;
state.players[action.payload.player].timeCurrent = 0;
state.players[action.payload.player].timeRemaining = 0;
@ -156,7 +183,10 @@ const mixerState = createSlice({
state.players[action.payload.player].tracklistItemID = -1;
state.players[action.payload.player].loadError = false;
},
itemLoadPercentage(state, action: PayloadAction<{ player: number, percent: number }>) {
itemLoadPercentage(
state,
action: PayloadAction<{ player: number; percent: number }>
) {
state.players[action.payload.player].loading = action.payload.percent;
},
itemLoadComplete(state, action: PayloadAction<{ player: number }>) {
@ -214,11 +244,9 @@ const mixerState = createSlice({
time: number;
}>
) {
state.players[action.payload.player].timeCurrent =
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;
state.players[action.payload.player].timeLength - action.payload.time;
},
setTimeLength(
state,
@ -227,8 +255,7 @@ const mixerState = createSlice({
time: number;
}>
) {
state.players[action.payload.player].timeLength =
action.payload.time;
state.players[action.payload.player].timeLength = action.payload.time;
},
toggleAutoAdvance(
state,
@ -277,8 +304,7 @@ const mixerState = createSlice({
id: number;
}>
) {
state.players[action.payload.player].tracklistItemID =
action.payload.id;
state.players[action.payload.player].tracklistItemID = action.payload.id;
},
startMicCalibration(state) {
state.mic.calibration = true;
@ -370,9 +396,7 @@ export const load = (
}
});
wavesurfer.on("play", () => {
dispatch(
mixerState.actions.setPlayerState({ player, state: "playing" })
);
dispatch(mixerState.actions.setPlayerState({ player, state: "playing" }));
});
wavesurfer.on("pause", () => {
dispatch(
@ -383,9 +407,7 @@ export const load = (
);
});
wavesurfer.on("finish", () => {
dispatch(
mixerState.actions.setPlayerState({ player, state: "stopped" })
);
dispatch(mixerState.actions.setPlayerState({ player, state: "stopped" }));
const state = getState().mixer.players[player];
if (state.tracklistItemID !== -1) {
dispatch(BroadcastState.tracklistEnd(state.tracklistItemID));
@ -444,9 +466,11 @@ export const load = (
const percent = progress.transferred / progress.total;
if (percent !== 1) {
console.log({ progress });
dispatch(mixerState.actions.itemLoadPercentage({ player, percent}));
dispatch(
mixerState.actions.itemLoadPercentage({ player, percent })
);
}
}
},
})
);
const rawData = await result.arrayBuffer();
@ -480,7 +504,10 @@ export const load = (
}
};
export const play = (player: number): AppThunk => async (dispatch, getState) => {
export const play = (player: number): AppThunk => async (
dispatch,
getState
) => {
if (typeof wavesurfers[player] === "undefined") {
console.log("nothing loaded");
return;
@ -498,9 +525,7 @@ export const play = (player: number): AppThunk => async (dispatch, getState) =>
if (state.loadedItem && "album" in state.loadedItem) {
//track
dispatch(
BroadcastState.tracklistStart(player, state.loadedItem.trackid)
);
dispatch(BroadcastState.tracklistStart(player, state.loadedItem.trackid));
}
};
@ -585,12 +610,8 @@ export const setVolume = (
playerGainTweens[player].tweens.forEach(tween => tween.pause());
if (playerGainTweens[player].target === level) {
delete playerGainTweens[player];
dispatch(
mixerState.actions.setPlayerVolume({ player, volume: uiLevel })
);
dispatch(
mixerState.actions.setPlayerGain({ player, gain: volume })
);
dispatch(mixerState.actions.setPlayerVolume({ player, volume: uiLevel }));
dispatch(mixerState.actions.setPlayerGain({ player, gain: volume }));
return;
}
}
@ -602,9 +623,7 @@ export const setVolume = (
const volumeTween = new Between(currentLevel, uiLevel)
.time(FADE_TIME_SECONDS * 1000)
.on("update", (val: number) => {
dispatch(
mixerState.actions.setPlayerVolume({ player, volume: val })
);
dispatch(mixerState.actions.setPlayerVolume({ player, volume: val }));
});
const gainTween = new Between(currentGain, volume)
.time(FADE_TIME_SECONDS * 1000)
@ -615,9 +634,7 @@ export const setVolume = (
}
})
.on("complete", () => {
dispatch(
mixerState.actions.setPlayerGain({ player, gain: volume })
);
dispatch(mixerState.actions.setPlayerGain({ player, gain: volume }));
// clean up when done
delete playerGainTweens[player];
});