Skip to content

michoball/video-chat-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ“ธ VIDEO CHAT ROOM

video chat app ๋ฉ”์ธ ์ด๋ฏธ์ง€

๋ฐ”๋กœ๊ฐ€๊ธฐ Go to the App

๐Ÿ˜„ ์†Œ๊ฐœ

์นœ๊ตฌ๋“ค๊ณผ ์†Œ๊ทœ๋ชจ ํ™”์ƒ์ฑ„ํŒ…์„ ์œ„ํ•œ ์†Œ๋ฐ•ํ•œ ๊ณต๊ฐ„!
๋ฉ€๋ฆฌ์‚ฌ๋Š” ์นœ๊ตฌ๋“ค๊ณผ ์–ผ๊ตด๋ณด๊ณ  ์žฌ๋ฏธ์žˆ๋Š” ์˜์ƒ์ด๋‚˜ ์‚ฌ์ง„๋ณด๋ฉฐ ์›ƒ๊ณ  ๋– ๋“ค๊ณ  ์‹ถ์–ด์„œ ๋งŒ๋“  App

์ฝ”๋กœ๋‚˜๊ฐ€ ํ•œ์ฐฝ ์‹ฌํ•  ๋•Œ ์นœ๊ตฌ๋“ค๊ณผ ๋งŒ๋‚˜์ง€๋Š” ๋ชปํ•˜๊ณ  ์•„์‰ฌ์šด๋Œ€๋กœ ์คŒ์„ ์ด์šฉํ•˜์—ฌ ๋น„๋Œ€๋ฉด ๋งŒ๋‚จ์„ ๊ฐ€์ง„๊ฒฝํ—˜์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐœ๋ฐœ
์นœํ•œ์นœ๊ตฌ๋ผ๋ฆฌ ์„œ๋กœ ํ™”๋ฉด์„ ์ผœ๊ณ  ์ˆ˜๋‹ค๋–จ๊ณ  ๊ฐ™์ด ์žฌ๋ฏธ์žˆ๋Š” ์˜์ƒ์„ ๋ณด๋ฉฐ ๋†€ ์ˆ˜ ์žˆ๋Š” ์ฐฝ๊ตฌ๋ฅผ ๋งˆ๋ จํ•˜๊ณ  ์‹ถ์–ด ๋งŒ๋“ค์–ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๐Ÿค– ๊ธฐ์ˆ ์Šคํƒ



Agora SDK

agora agora ๋กœ๊ณ 
๋‘˜๋Ÿฌ๋ณด๊ธฐ Agora

ํ•ด์™ธ ์œ ๋ช… ์†Œ์…œ ๋ฏธ๋””์–ด ClubHose ์—์„œ ์‹ค์‹œ๊ฐ„ ์Œ์„ฑ์ฑ„ํŒ…์„ ์œ„ํ•ด ์‚ฌ์šฉ๋œ ์„œ๋น„์Šค
Agora์—์„œ๋Š” WebRtc ๊ธฐ๋ฐ˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ข€ ๋” ๊ฐ„ํŽธํ•˜๊ฒŒ ๊ฐœ๋ฐœ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž์‚ฌ์˜ sdk๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์‹ค์‹œ๊ฐ„ ์˜์ƒ ํ†ตํ™” ์•ฑ ๊ตฌํ˜„์„ ๊ณ ๋ฏผํ•˜๋˜ ์ค‘ ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์œผ๋กœ ์œ ์ €๊ฐ„ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์„ ํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹Œ WebRtc ๊ธฐ์ˆ ์— ๋Œ€ํ•ด์„œ ํฅ๋ฏธ๊ฐ€ ์ƒ๊ฒผ๊ณ  ์ด ๊ธฐ์ˆ ์„ ๊ณต๋ถ€ํ•˜๋˜ ์ค‘ ์•Œ๊ฒŒ ๋œ Agora์˜ rtc sdk๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๐Ÿ’ป ๊ธฐ๋Šฅ

๊ธฐ๋Šฅ ์„ธ๋ถ€ ๋‚ด์šฉ ์‹œ์—ฐ ๋ชจ์Šต
์œ ์ € ๋กœ๊ทธ์ธ - ๊ธฐ๋ณธ์ ์ธ email, password ๋กœ๊ทธ์ธ๊ณผ google OAuth ๋กœ๊ทธ์ธ ์ง€์›
- ๋กœ๊ทธ์ธ์—์„œ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€์ „ํ™˜
Lobby์—์„œ ๊ฐ„๋‹จํ•œ Room CRUD ๊ธฐ๋Šฅ ์ง€์› - Join ์œผ๋กœ ์ƒˆ๋กœ์šด Room ์•„์ด๋”” ์ž…๋ ฅ ํ›„ ์ž…์žฅ
-Create ๋กœ ์ƒˆ๋กœ์šด Room ์ด๋ฆ„์œผ๋กœ ์ƒ์„ฑ
- ํŽธ์ง‘ ๋ฒ„ํŠผ์œผ๋กœ Room ์ด๋ฆ„ ํŽธ์ง‘(๋‚˜์—๊ฒŒ๋งŒ)
- ์‚ญ์ œ ๋ฒ„ํŠผ์œผ๋กœ Room ์‚ญ์ œ ( ๋‹ค๋ฅธ ์œ ์ €๋“ค์€ ๊ทธ๋Œ€๋กœ ์ž”๋ฅ˜, ์œ ์ €๊ฐ€ ์—†์„ ์‹œ DB์—์„œ ์™„์ „ ์‚ญ์ œ
Agora SDK๋ฅผ ํ™œ์šฉํ•œ ํ™”์ƒ ์ฑ„ํŒ… & ์‹ค์‹œ๊ฐ„ ๋ฉ”์„ธ์ง€ ๊ตํ™˜ - Agora SDK์˜ rtc-sdk ์™€ rtm sdk๋ฅผ ํ™œ์šฉํ•˜์—ฌ video call ๊ณผ message call ํŒŒํŠธ๋ฅผ ์ƒ์„ฑ
Room ์•ˆ์—์„œ ์œ ์ €๋“ค ํ™”๋ฉด big size ์กฐ์ • ๊ธฐ๋Šฅ - ๊ฐ ์œ ์ €๋“ค์˜ ํ™”๋ฉด ํด๋ฆญ ์‹œ big ์‚ฌ์ด์ฆˆ๋กœ ์ „ํ™˜
- Big ์‚ฌ์ด์ฆˆ ์œ ์ € ์ด์™ธ์—๋Š” small ์‚ฌ์ด์ฆˆ๊ฐ€ ๋จ
Setting ๋ฒ„ํŠผ์œผ๋กœ ๋ฉ”์ธ ํ…Œ๋งˆ ์ƒ‰ ๋ณ€๊ฒฝ & Room Id ๋ณต์‚ฌ ๊ธฐ๋Šฅ โš™๏ธ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ App ํ…Œ๋งˆ ์ƒ‰ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
๐Ÿ“„ ๋ฒ„ํŠผ์œผ๋กœ ํ˜„์žฌ Room Id ์นดํ”ผ
Room ์•ˆ ์˜์ƒ ์ปจํŠธ๋กค๋Ÿฌ ๊ธฐ๋Šฅ ์ง€์› - ์œ ์ €๊ฐ€ ์ปจํŠธ๋กค๋Ÿฌ์˜ ๊ฐ ๊ธฐ๋Šฅ๋“ค ํด๋ฆญ์‹œ ์Œ์†Œ๊ฑฐ, ํ™”๋ฉด ๋„๊ธฐ, ํ™”๋ฉด ๊ณต์œ , ๋ฐฉ ๋‚˜๊ฐ€๊ธฐ ๊ธฐ๋Šฅ ์ง€์›
ํ™”๋ฉด ๊ณต์œ  ๊ธฐ๋Šฅ contorl์˜ ๋‚ด ํ™”๋ฉด์„ ๊ณต์œ ๊ธฐ๋Šฅ์œผ๋กœ ํ™”๋ฉด์„ ๊ณต์œ 

SRC ํด๋” ๊ตฌ์กฐ

src
 |__asset
 |     | videoChatIcon-96x96.png
 |
 |__ components
 |             | message      -- ๋ฉ”์„ธ์ง€ ๋‚ด์šฉ๋ฌผ
 |             | messageCall  -- agora Rtm event ๋‹ค๋ฃจ๋Š” ๊ณณ 
 |             | privateRoute  --  ์œ ์ € ๋กœ๊ทธ์ธ ์ƒํƒœ ๋‹ค๋ฃจ๋Š” ๊ณณ 
 |             | roomForm     --  lobby ์—์„œ์˜ room join & create๊ธฐ๋Šฅ
 |             | roomInfo     --  room ์•ˆ ๋ฐฉ์˜ ์ •๋ณด ํ‘œ์‹œ๋ถ€๋ถ„ 
 |             | roomList     -- lobby์— ๋‚ด ๋ฐฉ ๋ฆฌ์ŠคํŠธ ํ‘œ์‹œ
 |             | setting      -- room ๋ฉ”์ธ ์ƒ‰์ƒ ๋ฐ”๊พธ๋Š” ๊ธฐ๋Šฅ
 |             | shareScreen  -- ํ™”๋ฉด ๊ณต์œ ๊ธฐ๋Šฅ
 |             | signIn       -- ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ
 |             | signUo       -- ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ
 |             | videoCall    -- agora Rtc event ๋‹ค๋ฃจ๋Š” ๊ณณ
 |             | videoControl -- ๋น„๋””์˜ค ์ปจํŠธ๋กค๋Ÿฌ ๊ธฐ๋Šฅ
 |             | videoPlayer  -- ๊ฐ ๋น„๋””์˜ค UI 
 |             | videos       -- ์ „์ฒด ๋น„๋””์˜ค UI ์…‹ํŒ…
 | 
 |__ context
 |         | color.context.js  -- ๋ฉ”์ธ ์ƒ‰์ƒ context
 |         | rtcContext.js     
 |         | rtmContext.js
 |         | userContext.js
 |
 |__ pages            --  react-router ๋ถ€๋ถ„
 |       | authentication
 |       | home
 |       | lobby
 |       | nav 
 |       | room
 | 
 |__ store           -- redux & redux-saga ๋ถ€๋ถ„
 |       | room
 |       | rtc
 |       | rtm
 |       | user
 |       | rootReducer.js    -- ๋ฆฌ๋“€์„œ ํ†ตํ•ฉ
 |       | rootSaga.js       -- ์‚ฌ๊ฐ€ ํ†ตํ•ฉ
 |       | store.js          -- redux store ์…‹ํŒ… (with redux-toolkit)
 |
 |__ UI              -- ์žฌ์‚ฌ์šฉ UI component ๋ชจ์Œ
 |    | button
 |    | formContainer
 |    | formInput
 |    | spinner
 |    | Icons.jsx         -- mui ์•„์ด์ฝ˜
 |    | Theme.config.js   -- styled-components ThemeProvider ๋ถ€๋ถ„
 | 
 |__ utill
 |      | firebase   -- firebase ์ดˆ๊ธฐ config ์…‹ํŒ… & auth & fireStore ๋ถ€๋ถ„
 |      | reducer    -- ์•ก์…˜ ์ƒ์„ฑ์ž
 |      | Agora.config.js  -- agora rtc client ๊ธฐ๋ณธ ์…‹ํŒ…
 | 
 |__ App.js
 |__ global.styles.js
 |__ index.js

๐Ÿ› ๏ธ ํŠน์ง•

Local user ํ™”๋ฉด, Remote user ํ™”๋ฉด, Share ํ™”๋ฉด๊ณผ ๋ด‡, Local ์‚ฌ์šฉ์ž ๊ทธ๋ฆฌ๊ณ  remote์‚ฌ์šฉ์ž ๋ฉ”์„ธ์ง€์— ๋”ฐ๋ฅธ ๋‹ค๋ฅธ UI ์ ์šฉ ๊ฐ„ํŽธํ™”๋ฅผ ๊ณ ๋ คํ•œ

Message Content & Video Player ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ

๊ฐ ์ƒํ™ฉ์— ๋งž๋Š” TYPE์„ ์ง€์ •, prop์œผ๋กœ ๋“ค์–ด์˜จ type์— ๋งž๋Š” style์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” getType ์ฝ”๋“œ ์ ์šฉ

VideoPlayer.jsx Code Snippet

export const VIDEO_TYPE_CLASS = {
 base: "base",
 local: "local",
 share: "share",
 small: "small",
};

const getVideoType = (VideoType = VIDEO_TYPE_CLASS.base, share) =>
 ({
   [VIDEO_TYPE_CLASS.base]: share ? SmallVideoContainer : BaseVideoContainer,
   [VIDEO_TYPE_CLASS.local]: LocalVideoContainer,
   [VIDEO_TYPE_CLASS.share]: ShareVideoContainer,
   [VIDEO_TYPE_CLASS.small]: SmallVideoContainer,
 }[VideoType]);

function VideoPlayer({ rtcUser, track, videoType }) {

 const CustomVideoContainer = getVideoType(videoType, share);

 return (
   <CustomVideoContainer>
     { video ์žฌ์ƒ์„ ์œ„ํ•œ ์ฝ”๋“œ }
   </CustomVideoContainer>
 );
}

export default VideoPlayer;

firebase Auth์˜ ๊ด€์ฐฐ์ž๋ฅผ ์ด์šฉ ์œ ์ €์˜ login ์„ธ์…˜์„ ๊ด€๋ฆฌ

firebase/auth์˜ onAuthStateChanged ๊ด€์ฐฐ์ž๋ฅผ ์ด์šฉ ์œ ์ €์˜ ๋กœ๊ทธ์ธ ๋กœ๊ทธ์•„์›ƒ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌ
์ดˆ๊ธฐ ๊ด€์ฐฐ์ž ์‚ฌ์šฉ๋ชจ์Šต firebase.auth.js & userContext.js Code Snippet

// firebase.auth
export const onAuthStateChangedListener = (callback) => onAuthStateChanged(auth, callback);
// userContext 
useEffect(() => {
  const unsubscribe = onAuthStateChangedListener(async (user) => {
    let userAuth = null;
    if (user) {
      const userSnapshot = await createUserDocumentFromAuth(user);
      userAuth = { id: userSnapshot.id, ...userSnapshot.data() };
    }
    setCurrentUser(userAuth);
  });
  return unsubscribe;
}, []);

redux-saga ์‚ฌ์šฉ ํ›„ ๋ชจ์Šต firebase.auth.js Snippet
์œ ์ € auth ์ƒํƒœ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์œ„ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ•ฉ์นจ

// firebase.auth
export const getCurrentUser = () => {
 return new Promise((resolve, reject) => {
   const unsubscribe = onAuthStateChanged(
     auth,
     (userAuth) => {
       unsubscribe();
       resolve(userAuth);
     },
     reject
   );
 });
};

์ด์Šˆ

  • Agora SDK ์—…๋ฐ์ดํŠธ์— ๋”ฐ๋ฅธ ๊ฒฝ๊ณ ๋ฌธ์ด ๊ณ„์† ๋ฐœ์ƒ์ค‘์ž…๋‹ˆ๋‹ค. ํ™•์ธ ์ค‘์— ์žˆ์œผ๋‚˜ ์•„๋งˆ ๋ฒ„์ „์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ๊ทธ์—๋”ฐ๋ผ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. (23.08)

  • Agora rtc SDK ์˜ ๋™์‹œ ํ™”์ƒ ํ†ตํ™” ์ง€์›์ธ์›์ด ์ตœ๋Œ€ 17๋ช…์œผ๋กœ ๋‚˜์™€ ์žˆ์ง€๋งŒ ์‹ค์ œ 5๋ช…์ด์„œ ํ†ตํ™”๋ฅผ ํ•œ ๊ฒฐ๊ณผ ์†๋„๊ฐ€ ํ˜„์ €ํžˆ ๋–จ์–ด์ง€๋Š” ๊ฒƒ์„ ๋Š๊ผˆ๋‹ค StackoverFlow์™€ Agora FAQ์— ๋ณด๋ฉด rtc v3 ์ดํ•˜์—์„œ๋Š” 7๋ช… ๋ฐ‘์˜ ์ธ์›์„ ์ถ”์ฒœํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜์™€ ์žˆ์–ด ํ™”์ƒํ†ตํ™” ์ธ์›์„ ๋Š˜๋ฆฌ๋Š” ๊ฒƒ์€ ํž˜๋“ค์–ด๋ณด์ธ๋‹ค.

    ๊ด€๋ จ๊ธ€ stackoverFlow ํด๋ฆญ Agora VideoCall FAQ ํด๋ฆญ

  • Agora ์ž์ฒด์ ์ธ ์ด์Šˆ ์ด์™ธ์— room์— ์œ ์ €๊ฐ€ ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค Agora rtc๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์ด user publish & unpublish Event๋ฅผ ๋“ฃ๊ณ  ์žˆ์–ด์„œ ์ˆ˜์ • ์ค‘์— ์žˆ๋‹ค.

  • Join Room Error
    ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ฐฉ id๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋ฐฉ์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ฉ˜ํŠธ๊ฐ€ ๋‚˜์˜ค๊ณ  ์›๋ž˜ ๋กœ๋น„์˜ ์ƒํƒœ๋กœ ๋˜๋Œ์•„๊ฐ€์•ผ ํ•˜์ง€๋งŒ ๋กœ๋”ฉ ํ™”๋ฉด์—์„œ ๋„˜์–ด๊ฐ€์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•ด์„œ ์ˆ˜์ •์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค. (22.10.12)

  • Custom Room Error
    lobby์—์„œ ๊ฐœ๋ณ„๋กœ ๋ฐฉ์ด๋ฆ„์„ ์„ค์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋Š”๋ฐ ์—ฌ๊ธฐ์„œ ๋ฐฉ์ด๋ฆ„์„ ๋ฐ”๊ฟ”๋„ lobby์— ์žˆ๋Š” ๋ชฉ๋ก์— ์ ์šฉ๋˜์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ–ˆ๋‹ค.
    ์ด๋ฆ„ ์ˆ˜์ •์€ user ์ปฌ๋ ‰์…˜์•ˆ์˜ myRooms ์ปฌ๋ ‰์…˜์— ์ ์šฉ๋˜๋Š”๋ฐ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ์ดํ„ฐ๋Š” rooms ์ปฌ๋ ‰์…˜์—์„œ ๊ฐ€์ ธ์™€์„œ ์ƒ๊ธด์˜ค๋ฅ˜์˜€๊ณ  ์ˆ˜์ •์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค. (22.10.24)

๐Ÿ“ Todo ๋ฆฌ์ŠคํŠธ

  • ๊ธฐ์กด ๋ฐ˜์‘ํ˜• ๋น„๋””์˜ค UI ๊ฐœ์„ 
  • lobby์—์„œ join๋ฒ„ํŠผ ux ์ˆ˜์ • & ์œ ์ €์˜ room list ์ตœ์‹ ๋ฒ„์ „์œผ๋กœ fetch ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ์„ 
  • TypeScript๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ •์ ์œผ๋กœ ํƒ€์ž…์„ ๋ช…์‹œํ•˜๊ณ  ์—ฌ๋Ÿฌ ๋ณ€์ˆ˜์™€ ํ•จ์ˆ˜์˜ ๋ชฉ์ ์„ ๋ถ„๋ช…ํžˆํ•˜๊ธฐ
  • ๋ฐฉ์— ์ฐธ์—ฌํ•œ ์œ ์ €๋“ค ์ด๋ฆ„ tag๋ฅผ video์— ๋ถ™์ด๊ธฐ
  • ์œ ์ € avatar ์ถ”๊ฐ€