Audio Video almost working; need to merge "users" and "peers"
This commit is contained in:
parent
642935764c
commit
45fd4c7006
@ -23,17 +23,19 @@ const Lobby: React.FC<LobbyProps> = (props: LobbyProps) => {
|
|||||||
const [global, setGlobal] = useState<GlobalContextType>({
|
const [global, setGlobal] = useState<GlobalContextType>({
|
||||||
connected: false,
|
connected: false,
|
||||||
ws: undefined,
|
ws: undefined,
|
||||||
|
sessionId: sessionId,
|
||||||
name: "",
|
name: "",
|
||||||
chat: [],
|
chat: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(global);
|
|
||||||
}, [global]);
|
|
||||||
|
|
||||||
const onWsMessage = (event: MessageEvent) => {
|
const onWsMessage = (event: MessageEvent) => {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
|
case "update":
|
||||||
|
if ("name" in data) {
|
||||||
|
setName(data.name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "error":
|
case "error":
|
||||||
setError(data.error);
|
setError(data.error);
|
||||||
break;
|
break;
|
||||||
|
@ -4,6 +4,7 @@ interface GlobalContextType {
|
|||||||
connected: boolean;
|
connected: boolean;
|
||||||
ws?: WebSocket;
|
ws?: WebSocket;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
sessionId?: string;
|
||||||
chat?: any[];
|
chat?: any[];
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
@ -12,6 +13,7 @@ const GlobalContext = createContext<GlobalContextType>({
|
|||||||
connected: false,
|
connected: false,
|
||||||
ws: undefined,
|
ws: undefined,
|
||||||
name: "",
|
name: "",
|
||||||
|
sessionId: undefined,
|
||||||
chat: []
|
chat: []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ const debug = true;
|
|||||||
|
|
||||||
// Types for peer and track context
|
// Types for peer and track context
|
||||||
interface Peer {
|
interface Peer {
|
||||||
name: string;
|
sessionId: string;
|
||||||
|
peerName: string;
|
||||||
hasAudio: boolean;
|
hasAudio: boolean;
|
||||||
hasVideo: boolean;
|
hasVideo: boolean;
|
||||||
attributes: Record<string, any>;
|
attributes: Record<string, any>;
|
||||||
@ -33,6 +34,7 @@ interface TrackContext {
|
|||||||
|
|
||||||
interface AddPeerConfig {
|
interface AddPeerConfig {
|
||||||
peer_id: string;
|
peer_id: string;
|
||||||
|
peer_name: string;
|
||||||
hasAudio: boolean;
|
hasAudio: boolean;
|
||||||
hasVideo: boolean;
|
hasVideo: boolean;
|
||||||
should_create_offer?: boolean;
|
should_create_offer?: boolean;
|
||||||
@ -85,7 +87,7 @@ type MediaAgentProps = {
|
|||||||
|
|
||||||
const MediaAgent = (props: MediaAgentProps) => {
|
const MediaAgent = (props: MediaAgentProps) => {
|
||||||
const { setPeers } = props;
|
const { setPeers } = props;
|
||||||
const { name, ws } = useContext(GlobalContext);
|
const { name, ws, sessionId } = useContext(GlobalContext);
|
||||||
const [peers] = useState<Record<string, Peer>>({});
|
const [peers] = useState<Record<string, Peer>>({});
|
||||||
const [track, setTrack] = useState<TrackContext | undefined>(undefined);
|
const [track, setTrack] = useState<TrackContext | undefined>(undefined);
|
||||||
const ignore = useRef(false);
|
const ignore = useRef(false);
|
||||||
@ -127,7 +129,7 @@ const MediaAgent = (props: MediaAgentProps) => {
|
|||||||
console.log(`media-agent - No local media track`);
|
console.log(`media-agent - No local media track`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const peer_id = config.peer_id;
|
const { peer_id, peer_name } = config;
|
||||||
if (peer_id in peers) {
|
if (peer_id in peers) {
|
||||||
if (!peers[peer_id].dead) {
|
if (!peers[peer_id].dead) {
|
||||||
/* This is normal when peers are added by other connecting
|
/* This is normal when peers are added by other connecting
|
||||||
@ -140,7 +142,8 @@ const MediaAgent = (props: MediaAgentProps) => {
|
|||||||
* have its peer state change and trigger an update from
|
* have its peer state change and trigger an update from
|
||||||
* <PlayerList> */
|
* <PlayerList> */
|
||||||
const peer: Peer = {
|
const peer: Peer = {
|
||||||
name: peer_id,
|
sessionId: peer_id,
|
||||||
|
peerName: peer_name,
|
||||||
hasAudio: config.hasAudio,
|
hasAudio: config.hasAudio,
|
||||||
hasVideo: config.hasVideo,
|
hasVideo: config.hasVideo,
|
||||||
attributes: {},
|
attributes: {},
|
||||||
@ -442,15 +445,16 @@ const MediaAgent = (props: MediaAgentProps) => {
|
|||||||
}, [ws, track, peers, setPeers, sendMessage]);
|
}, [ws, track, peers, setPeers, sendMessage]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!name) {
|
if (!sessionId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let update = false;
|
let update = false;
|
||||||
if (track) {
|
if (track) {
|
||||||
if (!(name in peers)) {
|
if (!(sessionId in peers)) {
|
||||||
update = true;
|
update = true;
|
||||||
peers[name] = {
|
peers[sessionId] = {
|
||||||
name: name,
|
peerName: name || "Unknown",
|
||||||
|
sessionId: sessionId,
|
||||||
local: true,
|
local: true,
|
||||||
muted: true,
|
muted: true,
|
||||||
videoOn: false,
|
videoOn: false,
|
||||||
@ -468,7 +472,7 @@ const MediaAgent = (props: MediaAgentProps) => {
|
|||||||
/* Renaming the local connection requires the peer to be deleted
|
/* Renaming the local connection requires the peer to be deleted
|
||||||
* and re-established with the signaling server */
|
* and re-established with the signaling server */
|
||||||
for (let key in peers) {
|
for (let key in peers) {
|
||||||
if (peers[key].local && key !== name) {
|
if (peers[key].local && key !== sessionId) {
|
||||||
delete peers[key];
|
delete peers[key];
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
@ -485,21 +489,27 @@ const MediaAgent = (props: MediaAgentProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type setup_local_media_props = {
|
||||||
|
audio?: boolean;
|
||||||
|
video?: boolean;
|
||||||
|
}
|
||||||
const setup_local_media = async (
|
const setup_local_media = async (
|
||||||
options: { audio?: boolean; video?: boolean } = { audio: true, video: true }
|
props?: setup_local_media_props
|
||||||
): Promise<TrackContext> => {
|
): Promise<TrackContext> => {
|
||||||
|
const { audio = true, video = true } = props ?? {};
|
||||||
// Ask user for permission to use the computers microphone and/or camera
|
// Ask user for permission to use the computers microphone and/or camera
|
||||||
console.log(
|
console.log(
|
||||||
`media-agent - Requesting access to local audio: ${!!options.audio} / video: ${!!options.video} inputs`
|
`media-agent - Requesting access to local audio: ${audio} / video: ${video} inputs`
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
const media = await navigator.mediaDevices.getUserMedia({
|
const media = await navigator.mediaDevices.getUserMedia({
|
||||||
audio: !!options.audio,
|
audio,
|
||||||
video: !!options.video,
|
video,
|
||||||
});
|
});
|
||||||
sendMessage({ type: "media_status", video: !!options.video, audio: !!options.audio });
|
sendMessage({ type: "media_status", video, audio });
|
||||||
// Optionally apply constraints
|
// Optionally apply constraints
|
||||||
if (options.video && media.getVideoTracks().length > 0) {
|
if (video && media.getVideoTracks().length > 0) {
|
||||||
|
console.log(`media-agent - Applying video constraints to ${media.getVideoTracks().length} video tracks`);
|
||||||
media.getVideoTracks().forEach((track) => {
|
media.getVideoTracks().forEach((track) => {
|
||||||
track.applyConstraints({
|
track.applyConstraints({
|
||||||
width: { min: 160, max: 320 },
|
width: { min: 160, max: 320 },
|
||||||
@ -507,13 +517,13 @@ const MediaAgent = (props: MediaAgentProps) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { media, audio: !!options.audio, video: !!options.video };
|
return { media, audio, video };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (options.video) {
|
if (video) {
|
||||||
console.log(`media-agent - Access to audio and video failed. Trying just audio.`);
|
console.log(`media-agent - Access to audio and video failed. Trying just audio.`);
|
||||||
// Try again with only audio if video failed
|
// Try again with only audio if video failed
|
||||||
return setup_local_media({ audio: options.audio, video: false });
|
return setup_local_media({ audio, video: false });
|
||||||
} else if (options.audio) {
|
} else if (audio) {
|
||||||
console.log(`media-agent - Access to audio failed.`);
|
console.log(`media-agent - Access to audio failed.`);
|
||||||
sendMessage({ type: "media_status", video: false, audio: false });
|
sendMessage({ type: "media_status", video: false, audio: false });
|
||||||
// Return a dummy context with no media
|
// Return a dummy context with no media
|
||||||
@ -530,14 +540,16 @@ const MediaAgent = (props: MediaAgentProps) => {
|
|||||||
if (debug) console.log(`media-agent - WebSocket open request. ` + `Attempting to create local media.`);
|
if (debug) console.log(`media-agent - WebSocket open request. ` + `Attempting to create local media.`);
|
||||||
setup_local_media()
|
setup_local_media()
|
||||||
.then((context) => {
|
.then((context) => {
|
||||||
|
console.log(`media-agent - local media setup complete`, context);
|
||||||
/* once the user has given us access to their
|
/* once the user has given us access to their
|
||||||
* microphone/camcorder, join the channel and start peering up */
|
* microphone/camcorder, join the channel and start peering up */
|
||||||
if (ignore.current) {
|
console.log(`media-agent - ignore set to ${ignore.current}`);
|
||||||
console.log(`media-agent - aborting setting local media`);
|
// if (ignore.current) {
|
||||||
} else {
|
// console.log(`media-agent - aborting setting local media`);
|
||||||
|
// } else {
|
||||||
console.log("media-agent - setTrack called with context:", context);
|
console.log("media-agent - setTrack called with context:", context);
|
||||||
setTrack(context);
|
setTrack(context);
|
||||||
}
|
// }
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
/* user denied access to a/v */
|
/* user denied access to a/v */
|
||||||
@ -572,8 +584,8 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (peer && peer.name) {
|
if (peer && peer.peerName) {
|
||||||
const el = document.querySelector(`.MediaControl[data-peer="${peer.name}"]`);
|
const el = document.querySelector(`.MediaControl[data-peer="${peer.sessionId}"]`);
|
||||||
setTarget(el ?? undefined);
|
setTarget(el ?? undefined);
|
||||||
}
|
}
|
||||||
}, [setTarget, peer]);
|
}, [setTarget, peer]);
|
||||||
@ -594,7 +606,7 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
|
|||||||
console.log(`media-control - render`);
|
console.log(`media-control - render`);
|
||||||
|
|
||||||
const toggleMute = (event: React.MouseEvent | React.TouchEvent) => {
|
const toggleMute = (event: React.MouseEvent | React.TouchEvent) => {
|
||||||
if (debug) console.log(`media-control - toggleMute - ${peer.name}`, !muted);
|
if (debug) console.log(`media-control - toggleMute - ${peer.peerName}`, !muted);
|
||||||
if (peer) {
|
if (peer) {
|
||||||
peer.muted = !muted;
|
peer.muted = !muted;
|
||||||
setMuted(peer.muted);
|
setMuted(peer.muted);
|
||||||
@ -603,11 +615,11 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleVideo = (event: React.MouseEvent | React.TouchEvent) => {
|
const toggleVideo = (event: React.MouseEvent | React.TouchEvent) => {
|
||||||
if (debug) console.log(`media-control - toggleVideo - ${peer.name}`, !videoOn);
|
if (debug) console.log(`media-control - toggleVideo - ${peer.peerName}`, !videoOn);
|
||||||
if (peer) {
|
if (peer) {
|
||||||
peer.videoOn = !videoOn;
|
peer.videoOn = !videoOn;
|
||||||
if (peer.videoOn && media) {
|
if (peer.videoOn && media) {
|
||||||
const video = document.querySelector(`video[data-id="${media.name}"]`) as HTMLVideoElement | null;
|
const video = document.querySelector(`video[data-id="${media.peerName}"]`) as HTMLVideoElement | null;
|
||||||
if (video && typeof video.play === "function") {
|
if (video && typeof video.play === "function") {
|
||||||
video.play();
|
video.play();
|
||||||
}
|
}
|
||||||
@ -622,7 +634,7 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (media.attributes.srcObject) {
|
if (media.attributes.srcObject) {
|
||||||
console.log(`media-control - audio enable - ${peer.name}:${!muted}`);
|
console.log(`media-control - audio enable - ${peer.peerName}:${!muted}`);
|
||||||
(media.attributes.srcObject.getAudioTracks() as MediaStreamTrack[]).forEach((track: MediaStreamTrack) => {
|
(media.attributes.srcObject.getAudioTracks() as MediaStreamTrack[]).forEach((track: MediaStreamTrack) => {
|
||||||
track.enabled = media.hasAudio && !muted;
|
track.enabled = media.hasAudio && !muted;
|
||||||
});
|
});
|
||||||
@ -634,7 +646,7 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (media.attributes.srcObject) {
|
if (media.attributes.srcObject) {
|
||||||
console.log(`media-control - video enable - ${peer.name}:${videoOn}`);
|
console.log(`media-control - video enable - ${peer.peerName}:${videoOn}`);
|
||||||
(media.attributes.srcObject.getVideoTracks() as MediaStreamTrack[]).forEach((track: MediaStreamTrack) => {
|
(media.attributes.srcObject.getVideoTracks() as MediaStreamTrack[]).forEach((track: MediaStreamTrack) => {
|
||||||
track.enabled = Boolean(media.hasVideo) && Boolean(videoOn);
|
track.enabled = Boolean(media.hasVideo) && Boolean(videoOn);
|
||||||
});
|
});
|
||||||
@ -651,9 +663,9 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', border: "3px solid green" }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', border: "3px solid green", minWidth: '200px', minHeight: '100px' }}>
|
||||||
<div className={`MediaControlSpacer ${className}`} />
|
<div className={`MediaControlSpacer ${className}`} />
|
||||||
<div className={`MediaControl ${className}`} data-peer={peer.name}>
|
<div className={`MediaControl ${className}`} data-peer={peer.sessionId}>
|
||||||
<div className="Controls">
|
<div className="Controls">
|
||||||
{isSelf && (
|
{isSelf && (
|
||||||
<div onTouchStart={toggleMute} onClick={toggleMute}>
|
<div onTouchStart={toggleMute} onClick={toggleMute}>
|
||||||
@ -712,7 +724,7 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
|
|||||||
/>
|
/>
|
||||||
<Video
|
<Video
|
||||||
className="Video"
|
className="Video"
|
||||||
data-id={media.name}
|
data-id={media.peerName}
|
||||||
autoPlay={true}
|
autoPlay={true}
|
||||||
srcObject={media.attributes.srcObject}
|
srcObject={media.attributes.srcObject}
|
||||||
{...media.attributes}
|
{...media.attributes}
|
||||||
|
@ -6,12 +6,15 @@ import { GlobalContext } from "./GlobalContext";
|
|||||||
import { MediaControl, MediaAgent } from "./MediaControl";
|
import { MediaControl, MediaAgent } from "./MediaControl";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
|
|
||||||
|
type User = {
|
||||||
|
name: string;
|
||||||
|
sessionId: string;
|
||||||
|
live: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
const UserList: React.FC = () => {
|
const UserList: React.FC = () => {
|
||||||
const { ws, name } = useContext(GlobalContext);
|
const { ws, name, sessionId } = useContext(GlobalContext);
|
||||||
const [users, setUsers] = useState<Record<string, any>>({});
|
const [users, setUsers] = useState<Record<string, User>>({});
|
||||||
const [unselected, setUneslected] = useState<string[]>([]);
|
|
||||||
const [state, setState] = useState<string>('lobby');
|
|
||||||
const [color, setColor] = useState<string | undefined>(undefined);
|
|
||||||
const [peers, setPeers] = useState<Record<string, any>>({});
|
const [peers, setPeers] = useState<Record<string, any>>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -55,7 +58,6 @@ const UserList: React.FC = () => {
|
|||||||
|
|
||||||
const userElements: JSX.Element[] = [];
|
const userElements: JSX.Element[] = [];
|
||||||
|
|
||||||
const inLobby = state === 'lobby';
|
|
||||||
const sortedUsers: any[] = [];
|
const sortedUsers: any[] = [];
|
||||||
|
|
||||||
for (let key in users) {
|
for (let key in users) {
|
||||||
@ -88,59 +90,31 @@ const UserList: React.FC = () => {
|
|||||||
|
|
||||||
sortedUsers.sort(sortUsers);
|
sortedUsers.sort(sortUsers);
|
||||||
|
|
||||||
/* Array of just names... */
|
|
||||||
unselected.sort((A: string, B: string) => {
|
|
||||||
/* active user first */
|
|
||||||
if (A === name) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (B === name) {
|
|
||||||
return +1;
|
|
||||||
}
|
|
||||||
/* Then sort alphabetically */
|
|
||||||
return A.localeCompare(B);
|
|
||||||
});
|
|
||||||
|
|
||||||
const videoClass = sortedUsers.length <= 2 ? 'Medium' : 'Small';
|
const videoClass = sortedUsers.length <= 2 ? 'Medium' : 'Small';
|
||||||
|
|
||||||
sortedUsers.forEach(user => {
|
sortedUsers.forEach((user : User) => {
|
||||||
const userName = user.name;
|
const userName = user.name;
|
||||||
const selectable = inLobby && (user.status === 'Not active' || color === user.color);
|
const isSelf = user.sessionId === sessionId;
|
||||||
|
console.log(`User: ${userName}, Is Self: ${isSelf}, hasPeer: ${peers[user.sessionId] ? 'Yes' : 'No'}`);
|
||||||
userElements.push(
|
userElements.push(
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', border: "3px solid magenta" }}
|
<Box key={userName} sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', border: "3px solid magenta" }}
|
||||||
data-selectable={selectable}
|
|
||||||
data-selected={user.color === color}
|
|
||||||
className="UserEntry"
|
className="UserEntry"
|
||||||
key={`user-${user.color}`}>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div className="Name">{userName ? userName : 'Available' }</div>
|
<div className="Name">{userName ? userName : 'Available' }</div>
|
||||||
{ userName && !user.live && <div className="NoNetwork"></div> }
|
{ userName && !user.live && <div className="NoNetwork"></div> }
|
||||||
</div>
|
</div>
|
||||||
{ userName && user.live && peers[userName] && <MediaControl className={videoClass} peer={peers[userName]} isSelf={user.color === color}/> }
|
{ userName && user.live && peers[user.sessionId] && <MediaControl className={videoClass} peer={peers[user.sessionId]} isSelf={isSelf}/> }
|
||||||
{ !userName && <div></div> }
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const waiting = unselected.map((user) => {
|
|
||||||
return <div className={user === name ? 'Self' : ''} key={user}>
|
|
||||||
<div>{ user }</div>
|
|
||||||
{peers[user] && <MediaControl className={'Small'} peer={peers[user]} isSelf={name === user}/>}
|
|
||||||
</div>
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper className={`UserList ${videoClass}`}>
|
<Paper className={`UserList ${videoClass}`}>
|
||||||
<MediaAgent setPeers={setPeers}/>
|
<MediaAgent setPeers={setPeers}/>
|
||||||
<List className="UserSelector">
|
<List className="UserSelector">
|
||||||
{ userElements }
|
{ userElements }
|
||||||
</List>
|
</List>
|
||||||
{ unselected && unselected.length !== 0 && <div className="Unselected">
|
|
||||||
<div>In lobby</div>
|
|
||||||
<div>
|
|
||||||
{ waiting }
|
|
||||||
</div>
|
|
||||||
</div> }
|
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -132,20 +132,22 @@ async def join(
|
|||||||
logger.info(f"{session.short}:{session.name} - Already joined to Audio.")
|
logger.info(f"{session.short}:{session.name} - Already joined to Audio.")
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"{lobby.short}: -> addPeer - {session.short}:{session.name}")
|
|
||||||
|
|
||||||
for peer in lobby.sessions.values():
|
for peer in lobby.sessions.values():
|
||||||
if not peer.ws:
|
if not peer.ws:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"{peer.short}:{peer.name} - No WebSocket connection. Skipping."
|
f"{peer.short}:{peer.name} - No WebSocket connection. Skipping."
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
logger.info(
|
||||||
|
f"{lobby.short}:{peer.name} -> addPeer - {session.short}:{session.name}"
|
||||||
|
)
|
||||||
# Add this caller to all peers
|
# Add this caller to all peers
|
||||||
await peer.ws.send_json(
|
await peer.ws.send_json(
|
||||||
{
|
{
|
||||||
"type": "addPeer",
|
"type": "addPeer",
|
||||||
"data": {
|
"data": {
|
||||||
"peer_id": session.id,
|
"peer_id": session.id,
|
||||||
|
"peer_name": session.name,
|
||||||
"should_create_offer": False,
|
"should_create_offer": False,
|
||||||
"has_audio": has_audio,
|
"has_audio": has_audio,
|
||||||
"has_video": has_video,
|
"has_video": has_video,
|
||||||
@ -158,7 +160,8 @@ async def join(
|
|||||||
{
|
{
|
||||||
"type": "addPeer",
|
"type": "addPeer",
|
||||||
"data": {
|
"data": {
|
||||||
"peer_id": peer,
|
"peer_id": peer.id,
|
||||||
|
"peer_name": peer.name,
|
||||||
"should_create_offer": True,
|
"should_create_offer": True,
|
||||||
"has_audio": peer.has_audio,
|
"has_audio": peer.has_audio,
|
||||||
"has_video": peer.has_video,
|
"has_video": peer.has_video,
|
||||||
@ -228,7 +231,9 @@ async def websocket_lobby(
|
|||||||
session = getSession(session_id)
|
session = getSession(session_id)
|
||||||
if not session:
|
if not session:
|
||||||
logger.error(f"{short}: Invalid session ID {session_id}")
|
logger.error(f"{short}: Invalid session ID {session_id}")
|
||||||
await websocket.send_json({"type": "error", "error": f"Invalid session ID {session_id}"})
|
await websocket.send_json(
|
||||||
|
{"type": "error", "error": f"Invalid session ID {session_id}"}
|
||||||
|
)
|
||||||
await websocket.close()
|
await websocket.close()
|
||||||
return
|
return
|
||||||
session.ws = websocket
|
session.ws = websocket
|
||||||
@ -264,13 +269,18 @@ async def websocket_lobby(
|
|||||||
logger.info(f"{session.short}: Name set to {session.name}")
|
logger.info(f"{session.short}: Name set to {session.name}")
|
||||||
await websocket.send_json({"type": "update", "name": name})
|
await websocket.send_json({"type": "update", "name": name})
|
||||||
case "list_users":
|
case "list_users":
|
||||||
users = [{"name": s.name, "live": True} for s in sessions.values()]
|
users = [
|
||||||
|
{"name": s.name, "live": True, "sessionId": s.id}
|
||||||
|
for s in sessions.values()
|
||||||
|
]
|
||||||
await websocket.send_json({"type": "users", "users": users})
|
await websocket.send_json({"type": "users", "users": users})
|
||||||
|
|
||||||
case 'media_status':
|
case "media_status":
|
||||||
has_audio = data.get("audio", False)
|
has_audio = data.get("audio", False)
|
||||||
has_video = data.get("video", False)
|
has_video = data.get("video", False)
|
||||||
logger.info(f"{session.short}: <- media-status - audio: {has_audio}, video: {has_video}")
|
logger.info(
|
||||||
|
f"{session.short}: <- media-status - audio: {has_audio}, video: {has_video}"
|
||||||
|
)
|
||||||
session.has_audio = has_audio
|
session.has_audio = has_audio
|
||||||
session.has_video = has_video
|
session.has_video = has_video
|
||||||
|
|
||||||
@ -283,18 +293,19 @@ async def websocket_lobby(
|
|||||||
await part(lobby, session)
|
await part(lobby, session)
|
||||||
|
|
||||||
case "relayICECandidate":
|
case "relayICECandidate":
|
||||||
if id not in lobby.sessions:
|
logger.info(data)
|
||||||
|
if session.id not in lobby.sessions:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"{session.short}:{session.name} <- relayICECandidate - Does not have Audio"
|
f"{session.short}:{session.name} <- relayICECandidate - Does not have Audio"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
peer_id = data.peer_id
|
peer_id = data.get("config", {}).get("peer_id")
|
||||||
candidate = data.candidate
|
candidate = data.get("config", {}).get("candidate")
|
||||||
|
|
||||||
message = {
|
message = {
|
||||||
type: "iceCandidate",
|
"type": "iceCandidate",
|
||||||
data: {"peer_id": session.id, "candidate": candidate},
|
"data": {"peer_id": session.id, "candidate": candidate},
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer_id in lobby.sessions:
|
if peer_id in lobby.sessions:
|
||||||
@ -312,13 +323,14 @@ async def websocket_lobby(
|
|||||||
logger.error(
|
logger.error(
|
||||||
f"{session.short}:{session.name} - relaySessionDescription - Does not have Audio"
|
f"{session.short}:{session.name} - relaySessionDescription - Does not have Audio"
|
||||||
)
|
)
|
||||||
|
peer_id = data.get("config", {}).get("peer_id")
|
||||||
peer_id = data.peer_id
|
session_description = data.get("config", {}).get(
|
||||||
session_description = data.session_description
|
"session_description"
|
||||||
|
)
|
||||||
message = {
|
message = {
|
||||||
type: "sessionDescription",
|
"type": "sessionDescription",
|
||||||
data: {
|
"data": {
|
||||||
"peer_id": session.name,
|
"peer_id": session.id,
|
||||||
"session_description": session_description,
|
"session_description": session_description,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -341,6 +353,12 @@ async def websocket_lobby(
|
|||||||
|
|
||||||
except WebSocketDisconnect:
|
except WebSocketDisconnect:
|
||||||
logger.info(f"WebSocket disconnected for user {session_id}")
|
logger.info(f"WebSocket disconnected for user {session_id}")
|
||||||
|
# Cleanup: remove session from lobby and sessions dict
|
||||||
|
session.ws = None
|
||||||
|
if lobby and session:
|
||||||
|
await part(lobby, session)
|
||||||
|
# if session_id in sessions:
|
||||||
|
# del sessions[session_id]
|
||||||
|
|
||||||
|
|
||||||
# Serve static files or proxy to frontend development server
|
# Serve static files or proxy to frontend development server
|
||||||
@ -355,7 +373,6 @@ if PRODUCTION:
|
|||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
logger.info(f"Proxying static files to http://static-frontend:3000 at {public_url}")
|
logger.info(f"Proxying static files to http://static-frontend:3000 at {public_url}")
|
||||||
|
|
||||||
import ssl
|
import ssl
|
||||||
@ -385,7 +402,8 @@ else:
|
|||||||
filtered_headers = {
|
filtered_headers = {
|
||||||
k: v
|
k: v
|
||||||
for k, v in proxy_resp.headers.items()
|
for k, v in proxy_resp.headers.items()
|
||||||
if k.lower() not in ["content-encoding", "transfer-encoding", "content-length"]
|
if k.lower()
|
||||||
|
not in ["content-encoding", "transfer-encoding", "content-length"]
|
||||||
}
|
}
|
||||||
return Response(
|
return Response(
|
||||||
content=content,
|
content=content,
|
||||||
@ -405,7 +423,7 @@ else:
|
|||||||
async def websocket_proxy(websocket: StarletteWebSocket):
|
async def websocket_proxy(websocket: StarletteWebSocket):
|
||||||
logger.info("WebSocket proxy connection established.")
|
logger.info("WebSocket proxy connection established.")
|
||||||
# Get scheme from websocket.url (should be 'ws' or 'wss')
|
# Get scheme from websocket.url (should be 'ws' or 'wss')
|
||||||
scheme = websocket.url.scheme if hasattr(websocket, 'url') else 'ws'
|
scheme = websocket.url.scheme if hasattr(websocket, "url") else "ws"
|
||||||
target_url = f"{scheme}://static-frontend:3000/ws"
|
target_url = f"{scheme}://static-frontend:3000/ws"
|
||||||
await websocket.accept()
|
await websocket.accept()
|
||||||
try:
|
try:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user