Added simple stream sharing
This commit is contained in:
parent
efd94a1821
commit
0bd1e86e48
@ -3,7 +3,7 @@ import { Text, Box, Input, Button, Label, IconButton, Flex } from "theme-ui";
|
|||||||
|
|
||||||
import Modal from "./Modal";
|
import Modal from "./Modal";
|
||||||
|
|
||||||
function Nickname({ nickname, allowChanging, onChange }) {
|
function Nickname({ nickname, allowChanging, onChange, onStream }) {
|
||||||
const [isChangeModalOpen, setIsChangeModalOpen] = useState(false);
|
const [isChangeModalOpen, setIsChangeModalOpen] = useState(false);
|
||||||
function openModal() {
|
function openModal() {
|
||||||
setIsChangeModalOpen(true);
|
setIsChangeModalOpen(true);
|
||||||
@ -32,16 +32,8 @@ function Nickname({ nickname, allowChanging, onChange }) {
|
|||||||
variant="caption"
|
variant="caption"
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
cursor: allowChanging ? "pointer" : "default",
|
|
||||||
":hover": allowChanging && {
|
|
||||||
color: "primary",
|
|
||||||
},
|
|
||||||
":active": allowChanging && {
|
|
||||||
color: "secondary",
|
|
||||||
},
|
|
||||||
position: "relative",
|
position: "relative",
|
||||||
}}
|
}}
|
||||||
onClick={() => allowChanging && openModal()}
|
|
||||||
>
|
>
|
||||||
{nickname}
|
{nickname}
|
||||||
{allowChanging && (
|
{allowChanging && (
|
||||||
@ -54,7 +46,33 @@ function Nickname({ nickname, allowChanging, onChange }) {
|
|||||||
position: "absolute",
|
position: "absolute",
|
||||||
bottom: "-2px",
|
bottom: "-2px",
|
||||||
}}
|
}}
|
||||||
|
aria-label="Start Radio Stream"
|
||||||
|
onClick={() => allowChanging && onStream()}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height="10"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="10"
|
||||||
|
fill="currentcolor"
|
||||||
|
>
|
||||||
|
<path d="M3.24 6.15C2.51 6.43 2 7.17 2 8v12c0 1.1.9 2 2 2h16c1.11 0 2-.9 2-2V8c0-1.1-.9-2-2-2H8.3l7.43-3c.46-.19.68-.71.49-1.17-.19-.46-.71-.68-1.17-.49L3.24 6.15zM7 20c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm13-8h-2v-1c0-.55-.45-1-1-1s-1 .45-1 1v1H4V9c0-.55.45-1 1-1h14c.55 0 1 .45 1 1v3z" />
|
||||||
|
</svg>
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
{allowChanging && (
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
width: "10px",
|
||||||
|
height: "10px",
|
||||||
|
padding: 0,
|
||||||
|
margin: "2px",
|
||||||
|
position: "absolute",
|
||||||
|
bottom: "-2px",
|
||||||
|
transform: "translateX(12px)",
|
||||||
|
}}
|
||||||
aria-label="Change Nickname"
|
aria-label="Change Nickname"
|
||||||
|
onClick={() => allowChanging && openModal()}
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@ -93,6 +111,7 @@ function Nickname({ nickname, allowChanging, onChange }) {
|
|||||||
Nickname.defaultProps = {
|
Nickname.defaultProps = {
|
||||||
allowChanging: false,
|
allowChanging: false,
|
||||||
onChange: () => {},
|
onChange: () => {},
|
||||||
|
onStream: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Nickname;
|
export default Nickname;
|
||||||
|
@ -3,8 +3,17 @@ import { Flex, Box, Text } from "theme-ui";
|
|||||||
|
|
||||||
import AddPartyMemberButton from "./AddPartyMemberButton";
|
import AddPartyMemberButton from "./AddPartyMemberButton";
|
||||||
import Nickname from "./Nickname";
|
import Nickname from "./Nickname";
|
||||||
|
import Stream from "./Stream";
|
||||||
|
|
||||||
function Party({ nickname, partyNicknames, gameId, onNicknameChange }) {
|
function Party({
|
||||||
|
nickname,
|
||||||
|
partyNicknames,
|
||||||
|
gameId,
|
||||||
|
onNicknameChange,
|
||||||
|
stream,
|
||||||
|
partyStreams,
|
||||||
|
onStreamStart,
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
p={3}
|
p={3}
|
||||||
@ -36,10 +45,19 @@ function Party({ nickname, partyNicknames, gameId, onNicknameChange }) {
|
|||||||
nickname={nickname || ""}
|
nickname={nickname || ""}
|
||||||
allowChanging
|
allowChanging
|
||||||
onChange={onNicknameChange}
|
onChange={onNicknameChange}
|
||||||
|
onStream={onStreamStart}
|
||||||
/>
|
/>
|
||||||
{Object.entries(partyNicknames).map(([id, partyNickname]) => (
|
{Object.entries(partyNicknames).map(([id, partyNickname]) => (
|
||||||
<Nickname nickname={partyNickname} key={id} />
|
<Nickname nickname={partyNickname} key={id} />
|
||||||
))}
|
))}
|
||||||
|
{(stream || Object.keys(partyStreams).length !== 0) && (
|
||||||
|
<Text>Streams</Text>
|
||||||
|
)}
|
||||||
|
{stream && <Stream stream={stream} muted />}
|
||||||
|
{partyStreams &&
|
||||||
|
Object.entries(partyStreams).map(([id, partyStream]) => (
|
||||||
|
<Stream stream={partyStream} key={id} />
|
||||||
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<AddPartyMemberButton gameId={gameId} />
|
<AddPartyMemberButton gameId={gameId} />
|
||||||
|
26
src/components/Stream.js
Normal file
26
src/components/Stream.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React, { useRef, useEffect } from "react";
|
||||||
|
|
||||||
|
function Stream({ stream, muted }) {
|
||||||
|
const videoRef = useRef();
|
||||||
|
useEffect(() => {
|
||||||
|
if (videoRef.current) {
|
||||||
|
videoRef.current.srcObject = stream;
|
||||||
|
}
|
||||||
|
}, [stream]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<video
|
||||||
|
ref={videoRef}
|
||||||
|
autoPlay
|
||||||
|
playsInline
|
||||||
|
muted={muted}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream.defaultProps = {
|
||||||
|
muted: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Stream;
|
@ -6,7 +6,13 @@ import Peer from "../helpers/Peer";
|
|||||||
|
|
||||||
const socket = io("https://broker.owlbear.rodeo");
|
const socket = io("https://broker.owlbear.rodeo");
|
||||||
|
|
||||||
function useSession(partyId, onPeerConnected, onPeerDisconnected, onPeerData) {
|
function useSession(
|
||||||
|
partyId,
|
||||||
|
onPeerConnected,
|
||||||
|
onPeerDisconnected,
|
||||||
|
onPeerData,
|
||||||
|
onPeerStream
|
||||||
|
) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
socket.emit("join party", partyId);
|
socket.emit("join party", partyId);
|
||||||
}, [partyId]);
|
}, [partyId]);
|
||||||
@ -32,6 +38,10 @@ function useSession(partyId, onPeerConnected, onPeerDisconnected, onPeerData) {
|
|||||||
onPeerData && onPeerData({ id, peer, data });
|
onPeerData && onPeerData({ id, peer, data });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
peer.on("stream", (stream) => {
|
||||||
|
onPeerStream && onPeerStream({ id, peer, stream });
|
||||||
|
});
|
||||||
|
|
||||||
peer.on("close", () => {
|
peer.on("close", () => {
|
||||||
onPeerDisconnected && onPeerDisconnected(id);
|
onPeerDisconnected && onPeerDisconnected(id);
|
||||||
});
|
});
|
||||||
@ -83,7 +93,7 @@ function useSession(partyId, onPeerConnected, onPeerDisconnected, onPeerData) {
|
|||||||
socket.removeListener("joined party", handleJoinedParty);
|
socket.removeListener("joined party", handleJoinedParty);
|
||||||
socket.removeListener("signal", handleSignal);
|
socket.removeListener("signal", handleSignal);
|
||||||
};
|
};
|
||||||
}, [peers, onPeerConnected, onPeerDisconnected, onPeerData]);
|
}, [peers, onPeerConnected, onPeerDisconnected, onPeerData, onPeerStream]);
|
||||||
|
|
||||||
return { peers, socket };
|
return { peers, socket };
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ function Game() {
|
|||||||
gameId,
|
gameId,
|
||||||
handlePeerConnected,
|
handlePeerConnected,
|
||||||
handlePeerDisconnected,
|
handlePeerDisconnected,
|
||||||
handlePeerData
|
handlePeerData,
|
||||||
|
handlePeerStream
|
||||||
);
|
);
|
||||||
|
|
||||||
const [mapSource, setMapSource] = useState(null);
|
const [mapSource, setMapSource] = useState(null);
|
||||||
@ -70,8 +71,13 @@ function Game() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [stream, setStream] = useState(null);
|
||||||
|
const [partyStreams, setPartyStreams] = useState({});
|
||||||
function handlePeerConnected({ peer }) {
|
function handlePeerConnected({ peer }) {
|
||||||
peer.send({ id: "nickname", data: { [socket.id]: nickname } });
|
peer.send({ id: "nickname", data: { [socket.id]: nickname } });
|
||||||
|
if (stream) {
|
||||||
|
peer.addStream(stream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePeerData({ data, peer }) {
|
function handlePeerData({ data, peer }) {
|
||||||
@ -107,10 +113,28 @@ function Game() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handlePeerStream({ id, stream: partyStream }) {
|
||||||
|
setPartyStreams((prevStreams) => ({
|
||||||
|
...prevStreams,
|
||||||
|
[id]: partyStream,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function handlePeerDisconnected(disconnectedId) {
|
function handlePeerDisconnected(disconnectedId) {
|
||||||
setPartyNicknames((prevNicknames) => omit(prevNicknames, [disconnectedId]));
|
setPartyNicknames((prevNicknames) => omit(prevNicknames, [disconnectedId]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleStreamStart() {
|
||||||
|
navigator.mediaDevices
|
||||||
|
.getDisplayMedia({ video: true, audio: true })
|
||||||
|
.then((mediaStream) => {
|
||||||
|
setStream(mediaStream);
|
||||||
|
for (let peer of Object.values(peers)) {
|
||||||
|
peer.addStream(mediaStream);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex sx={{ flexDirection: "column", height: "100%" }}>
|
<Flex sx={{ flexDirection: "column", height: "100%" }}>
|
||||||
<Flex
|
<Flex
|
||||||
@ -121,6 +145,9 @@ function Game() {
|
|||||||
partyNicknames={partyNicknames}
|
partyNicknames={partyNicknames}
|
||||||
gameId={gameId}
|
gameId={gameId}
|
||||||
onNicknameChange={handleNicknameChange}
|
onNicknameChange={handleNicknameChange}
|
||||||
|
stream={stream}
|
||||||
|
partyStreams={partyStreams}
|
||||||
|
onStreamStart={handleStreamStart}
|
||||||
/>
|
/>
|
||||||
<Map
|
<Map
|
||||||
mapSource={mapSource}
|
mapSource={mapSource}
|
||||||
|
Loading…
Reference in New Issue
Block a user