Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIRE-208-study-webrtc-세미나-준비-윤영기 #21

Merged
merged 21 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
SKIP_PREFLIGHT_CHECK=true
REACT_APP_SERVER=http://172.16.101.93:8282/rooms
REACT_APP_SOCKET_URL=http:/localhost:3333/chat
REACT_APP_SERVER=https://172.16.101.93:3333/rooms
REACT_APP_SOCKET_URL=https://172.16.101.93:3333/room
REACT_APP_ROOM=http://172.16.101.93:8282/room
REACT_APP_SEND_USER_INFORMATION_URL=http://localhost:3333/users
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
{ "extensions": [".js", ".jsx", ".ts", ".tsx"] }
],
"jsx-a11y/no-noninteractive-element-interactions": 0,
"@typescript-eslint/explicit-module-boundary-types": 0
"@typescript-eslint/explicit-module-boundary-types": 0,
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
},
"settings": {
"import/resolver": {
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*

*.pem
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"arrowParens": "always",
"orderedImports": true,
"bracketSpacing": true,
"jsxBracketSameLine": false
"jsxBracketSameLine": false,
"endOfLine": "auto"
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"scripts": {
"start": "react-scripts start",
"start:https": "HTTPS=true SSL_CRT_FILE=localhost.pem SSL_KEY_FILE=localhost-key.pem react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
Expand Down
5 changes: 5 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- <meta
http-equiv="Content-Security-Policy"
content="upgrade-insecure-requests"
/> -->

<title>🇰🇷MODOCO</title>
</head>
<body>
Expand Down
25 changes: 0 additions & 25 deletions src/components/atoms/Button.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import RoomBlock from './RoomBlock';
import roomInterface from '../../interface/room.interface';
import roomsData from '../../rooms.json';

export default function Room() {
export default function RoomBlocks() {
const [rooms, setRooms] = useState(roomsData);
useEffect(() => {
const API_URL: string = process.env.REACT_APP_SERVER as string;
Expand Down
12 changes: 11 additions & 1 deletion src/components/rtc/components/LocalVideo.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { forwardRef } from 'react';
import { Video, VideoContainer } from './Video';
import styled from 'styled-components';

export const LocalVideo = forwardRef<
HTMLVideoElement,
Expand All @@ -12,3 +12,13 @@ export const LocalVideo = forwardRef<
);
});
LocalVideo.displayName = 'Video';

export const VideoContainer = styled.div`
box-sizing: border-box;
position: relative;
`;

export const Video = styled.video`
height: 100%;
width: 100%;
`;
99 changes: 51 additions & 48 deletions src/components/rtc/components/PeerConnectionSession.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,57 @@
/* eslint-disable lines-between-class-members */
import io from 'socket.io-client';
import io, { Socket } from 'socket.io-client';

const { RTCPeerConnection, RTCSessionDescription } = window;

class PeerConnectionSession {
mOnConnected;
mOnDisconnected;
mRoom;
mRoom: string;
socket: Socket;
peerConnections = {};
senders = [];
listeners = {};
socket;

constructor(socket) {
constructor(socket: Socket) {
this.socket = socket;
this.onCallMade();
}

addPeerConnection(id, stream, callback) {
/**
* @brief - 새로운 peer connection을 생성하고, peer connection object에 추가한다
* @param id
* @param stream
* @param callback
*/

addPeerConnection(
id: string,
stream: MediaStream,
callback: (_stream: MediaStream) => void,
) {
// 새로운 stun 서버에 추가
this.peerConnections[id] = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
});

// user의 media track을 추가
stream.getTracks().forEach((track) => {
this.senders.push(this.peerConnections[id].addTrack(track, stream));
});

this.listeners[id] = (event) => {
let fn;
if (this.peerConnections[id].connectionState === 'connected') {
console.log('mOnConnected', this.mOnConnected);
fn = this.mOnConnected;
} else if (this.peerConnections[id].connectionState === 'disconnected') {
console.log('mOnDisconnected', this.mOnDisconnected);
fn = this.mOnDisconnected;
} else {
console.log('mRoom', this.mRoom);
fn = this.mRoom;
}
if (fn === null) {
fn(event, id);
}
};

this.peerConnections[id].addEventListener(
'connectionstatechange',
this.listeners[id],
);

this.peerConnections[id].ontrack = function ({
streams: [stream],
}: {
streams;
}) {
// peerConnection의 track마다 생성된 stream을 callback함수로 전달
this.peerConnections[id].ontrack = ({ streams: [stream] }) => {
console.log({ id, stream });
callback(stream);
};

console.log(this.peerConnections);
// end of addPeerConnection
}

/**
* @breif 해당하는 peer connection을 삭제
* @param id 에 해당하는 peer connection 삭제
* 해당하는 peerConnection의 eventListener를 삭제
*/
removePeerConnection(id: string) {
this.peerConnections[id].removeEventListener(
'connectionstatechange',
Expand All @@ -70,6 +63,10 @@ class PeerConnectionSession {

isAlreadyCalling = false;

/**
* @brief 누구에게 전화를 걸지 RTCSession 생성 후 call
* @param to 에게 call -> socket 연결
*/
async callUser(to: string) {
if (this.peerConnections[to].iceConnectionState === 'new') {
const offer = await this.peerConnections[to].createOffer();
Expand All @@ -81,19 +78,20 @@ class PeerConnectionSession {
}
}

onConnected(callback) {
this.mOnConnected = callback;
}

onDisconnected(callback) {
this.mOnDisconnected = callback;
}
/**
* @onConnected @onDisconnected @joinRoom -> state에 따라 callback
* @param callback
*/

joinRoom(room) {
joinRoom(room: string) {
this.mRoom = room;
this.socket.emit('joinRoom', room);
}

/**
* @onCallMade 만들어 졌을 때 알려주는 함수
*/

onCallMade() {
this.socket.on('call-made', async (data) => {
await this.peerConnections[data.socket].setRemoteDescription(
Expand All @@ -103,33 +101,32 @@ class PeerConnectionSession {
await this.peerConnections[data.socket].setLocalDescription(
new RTCSessionDescription(answer),
);

this.socket.emit('make-answer', {
answer,
to: data.socket,
});
});
}

onAddUser(callback) {
onAddUser(callback: (_user: string) => void) {
this.socket.on(`${this.mRoom}-add-user`, async ({ user }) => {
callback(user);
});
}

onRemoveUser(callback) {
onRemoveUser(callback: (_socketId: string) => void) {
this.socket.on(`${this.mRoom}-remove-user`, ({ socketId }) => {
callback(socketId);
});
}

onUpdateUserList(callback) {
onUpdateUserList(callback: (_users: string[], _current: string) => void) {
this.socket.on(`${this.mRoom}-update-user-list`, ({ users, current }) => {
callback(users, current);
});
}

onAnswerMade(callback) {
onAnswerMade(callback: (_answer: string) => void) {
this.socket.on('answer-made', async (data) => {
await this.peerConnections[data.socket].setRemoteDescription(
new RTCSessionDescription(data.answer),
Expand All @@ -147,8 +144,14 @@ class PeerConnectionSession {
}
}

/**
*
* @brief socket 연결
* @returns {PeerConnectionSession} : 연결된 소켓에 해당하는 class
*/

export const createPeerConnectionContext = () => {
const socket = io('http://172.16.101.93:8282/room');
const socket = io(process.env.REACT_APP_SOCKET_URL as string);
console.log(socket);
return new PeerConnectionSession(socket);
};
30 changes: 21 additions & 9 deletions src/components/rtc/components/RemoteVideo.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
/* eslint-disable react/jsx-props-no-spreading */
/* eslint-disable react/destructuring-assignment */
import React, { useEffect, useState } from 'react';
import { Video, VideoContainer } from './Video';
import React, { useEffect } from 'react';
import styled from 'styled-components';

export function RemoteVideo(props) {
type MediaProvider = MediaStream | MediaSource | Blob;
const [mediaStream, setMediaStream] = useState<MediaProvider>();
interface Props {
key: string;
id: string;
autoPlay: boolean;
playsInline: boolean;
muted: boolean;
}

export function RemoteVideo(props: Props) {
useEffect(() => {
console.log('props', props);
const interval = setInterval(() => {
const remote = document.getElementById(
props.id,
) as HTMLVideoElement | null;
const stream = remote?.srcObject;

if (stream) {
setMediaStream(stream);
// setMediaStream(stream);
clearInterval(interval);
console.log(mediaStream);
}
console.log('remote', stream);
}, 100);

return () => {
Expand All @@ -33,3 +36,12 @@ export function RemoteVideo(props) {
</VideoContainer>
);
}
const VideoContainer = styled.div`
box-sizing: border-box;
position: relative;
`;

const Video = styled.video`
height: 100%;
width: 100%;
`;
14 changes: 0 additions & 14 deletions src/components/rtc/components/Video.tsx

This file was deleted.

22 changes: 13 additions & 9 deletions src/components/rtc/hooks/useCreateMediaStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@ export const useCreateMediaStream = (
localVideoRef: RefObject<HTMLVideoElement>,
) => {
const [userMediaStream, setUserMediaStream] = useState<MediaStream>();

/**
* @stream getUserMedia - webCam
* @stream getDisplayMedia - screen
*/
useEffect(() => {
const createMediaStream = async () => {
const stream: MediaStream = await navigator.mediaDevices.getUserMedia({
video: {
width: { min: 640, ideal: 1920 },
height: { min: 400, ideal: 1080 },
aspectRatio: { ideal: 1.7777777778 },
},
audio: true,
});
let stream: MediaStream = null;
try {
stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true,
});
} catch (e) {
console.log('cannot get display');
}

if (localVideoRef.current) {
localVideoRef.current.srcObject = stream;
Expand Down
Loading