TeaWeb/shared/js/connection/rtc/video/VideoClient.ts

100 lines
No EOL
3.4 KiB
TypeScript

import {
VideoBroadcastState,
VideoBroadcastType,
VideoClient,
VideoClientEvents
} from "tc-shared/connection/VideoConnection";
import {Registry} from "tc-shared/events";
import {RemoteRTPTrackState, RemoteRTPVideoTrack} from "../RemoteTrack";
import {LogCategory, logWarn} from "tc-shared/log";
import { tr } from "tc-shared/i18n/localize";
export class RtpVideoClient implements VideoClient {
private readonly clientId: number;
private readonly events: Registry<VideoClientEvents>;
private readonly listenerTrackStateChanged: {[T in VideoBroadcastType]} = {
screen: event => this.handleTrackStateChanged("screen", event.newState),
camera: event => this.handleTrackStateChanged("camera", event.newState)
};
private currentTrack: {[T in VideoBroadcastType]: RemoteRTPVideoTrack} = {
camera: undefined,
screen: undefined
};
private trackStates: {[T in VideoBroadcastType]: VideoBroadcastState} = {
camera: VideoBroadcastState.Stopped,
screen: VideoBroadcastState.Stopped
}
constructor(clientId: number) {
this.clientId = clientId;
this.events = new Registry<VideoClientEvents>();
}
getClientId(): number {
return this.clientId;
}
getEvents(): Registry<VideoClientEvents> {
return this.events;
}
getVideoStream(broadcastType: VideoBroadcastType): MediaStream {
return this.currentTrack[broadcastType]?.getMediaStream();
}
getVideoState(broadcastType: VideoBroadcastType): VideoBroadcastState {
return this.trackStates[broadcastType];
}
destroy() {
this.setRtpTrack("camera", undefined);
this.setRtpTrack("screen", undefined);
}
getRtpTrack(type: VideoBroadcastType) : RemoteRTPVideoTrack | undefined {
return this.currentTrack[type];
}
setRtpTrack(type: VideoBroadcastType, track: RemoteRTPVideoTrack | undefined) {
if(this.currentTrack[type]) {
this.currentTrack[type].getEvents().off("notify_state_changed", this.listenerTrackStateChanged[type]);
}
this.currentTrack[type] = track;
if(this.currentTrack[type]) {
this.currentTrack[type].getEvents().on("notify_state_changed", this.listenerTrackStateChanged[type]);
this.handleTrackStateChanged(type, this.currentTrack[type].getState());
}
}
private setBroadcastState(type: VideoBroadcastType, state: VideoBroadcastState) {
if(this.trackStates[type] === state) {
return;
}
const oldState = this.trackStates[type];
this.trackStates[type] = state;
this.events.fire("notify_broadcast_state_changed", { broadcastType: type, oldState: oldState, newState: state });
}
private handleTrackStateChanged(type: VideoBroadcastType, newState: RemoteRTPTrackState) {
switch (newState) {
case RemoteRTPTrackState.Bound:
case RemoteRTPTrackState.Unbound:
this.setBroadcastState(type, VideoBroadcastState.Stopped);
break;
case RemoteRTPTrackState.Started:
this.setBroadcastState(type, VideoBroadcastState.Running);
break;
case RemoteRTPTrackState.Destroyed:
logWarn(LogCategory.VIDEO, tr("Received new track state 'Destroyed' which should never happen."));
this.setBroadcastState(type, VideoBroadcastState.Stopped);
break;
}
}
}