WebRTC?

WebRTC(Web Real-Time Communication)는 웹 브라우저와 모바일에서 플러그인이나 추가 소프트웨어 없이 실시간으로 통신하게 해주는 기술로, WebRTC를 통해 음성 통화, 비디오 통화, 파일 공유 등을 웹 브라우저만으로 할 수 있게 해준다.

 

주요기능

1. 음성 및 비디오 통화

2. 데이터 공유

 

 

WebRTC 구성요소

1. getUserMedia: 사용자의 장치(카메라, 마이크 등)에서 미디어 스트림을 가져온다.

- 사용자에게 장치에 대한 권한을 요청하고, 비디오와 오디오 데이터를 캡쳐할 수 있다.

 

2. RTCPeerConnection: 두 브라우저 간의 직접 연결을 설정하고 관리한다.

- 피어 간의 미디어 스트림을 주고받을 수 있다.

 

3. ICE (Interactice Connectivity Establishment): 피어간의 연결을 설정하고 유지하는 데 도움을 준다.

- NAT 및 방화벽을 통과하여 두 브라우저가 서로 연결될 수 있도록 한다.

 

 

WebRTC의 작동 방식

1. 미디어 캡처 : 'getUserMedia'를 사용하여 사용자의 카메라와 마이크에서 미디어 스트림을 캡처한다

2. 피어 연결 설정: 'RTCPeerConnection'을 사용하여 두 브라우저 간의 연결을 설정한다. 이 과정에서 ICE 프로토콜을 사용하여 서로의 네트워크 환경에 맞는 최적의 경로를 찾는다.

3. 신호 교환: 두 브라우저가 서로 연결되기 위해 서버를 통해서 신호 교환을 한다.

- Offer/Answer: 한 브라우저가 연결 요청(Offer)을 보내면, 다른 브라우저는 이를 수락(Answer)한다.

- ICE Candidates: 연결을 설정하기 위해 서로의 네트워크 정보(ICE Candidates)를 교환한다.

4. 미디어 스트림 전송: 연결이 설정되면, 두 브라우저는 직접 미디어 스트림을 주고 받을 수 있다.

 

SIP?

SIP(Session Initiation Protocol)은 통신 세션을 제어하기 위한 프로토콜이다.

OSI 7계층의 응용계층에 속하며, TCP, UDP 모두 사용가능하며 Request/Response 구조이다.

인터넷전화, 멀티미디어 배포 회의가 포함이 되며 SIP는 이를 설정, 수정, 종료할 수 있는 시그널링 프로토콜이다.

 

React + Typescript 환경에서 WebRTC + SIP로 통화기능 구현하기

1. 프로젝트 생성

npx create-react-app webrtc-app --template typescript

 

 

2. 패키지 설치

npm install socket.io-client
npm install jssip // 통화 기능을 위한 라이브러리

 

 

3. Socket.io 설정

'src/socket.ts'

import { io } from 'socket.io-client';

const socket = io('http://localhost:5000');  // 서버 주소에 맞게 변경

export default socket;

 

 

4. 미디어 스트림 설정

사용자의 비디오와 오디오 스트림을 가져오는 방법 설정

// 'src/hooks/useMediaStream.ts'
import { useEffect, useState } from 'react';

const useMediaStream = () => {
    const [stream, setStream] = useState<MediaStream | null>(null);

    useEffect(() => {
        const getMediaStream = async () => {
            try {
                const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
                setStream(mediaStream);
            } catch (error) {
                console.error('Error accessing media devices.', error);
            }
        };

        getMediaStream();
    }, []);

    return stream;
};

export default useMediaStream;

 

 

5. RTCPeerConnection 설정

"RTCPeerConnection"을 설정하고 연결 과정을 관리하는 훅 생성

// 'src/hooks/usePeerConnection.ts'
import { useEffect, useRef } from 'react';
import socket from '../socket';

const usePeerConnection = (localStream: MediaStream | null) => {
    const peerConnection = useRef<RTCPeerConnection | null>(null);

    useEffect(() => {
        if (!localStream) return;

        peerConnection.current = new RTCPeerConnection({
            iceServers: [
                {
                    urls: 'stun:stun.l.google.com:19302'
                }
            ]
        });

        peerConnection.current.onicecandidate = event => {
            if (event.candidate) {
                socket.emit('ice-candidate', event.candidate);
            }
        };

        peerConnection.current.ontrack = event => {
            // 리모트 스트림을 설정하는 곳
        };

        localStream.getTracks().forEach(track => {
            peerConnection.current?.addTrack(track, localStream);
        });

        socket.on('ice-candidate', (candidate: RTCIceCandidate) => {
            peerConnection.current?.addIceCandidate(new RTCIceCandidate(candidate));
        });

        socket.on('offer', async (offer: RTCSessionDescriptionInit) => {
            if (peerConnection.current) {
                await peerConnection.current.setRemoteDescription(new RTCSessionDescription(offer));
                const answer = await peerConnection.current.createAnswer();
                await peerConnection.current.setLocalDescription(answer);
                socket.emit('answer', answer);
            }
        });

        socket.on('answer', async (answer: RTCSessionDescriptionInit) => {
            if (peerConnection.current) {
                await peerConnection.current.setRemoteDescription(new RTCSessionDescription(answer));
            }
        });

        return () => {
            peerConnection.current?.close();
            peerConnection.current = null;
        };
    }, [localStream]);

    const createOffer = async () => {
        if (peerConnection.current) {
            const offer = await peerConnection.current.createOffer();
            await peerConnection.current.setLocalDescription(offer);
            socket.emit('offer', offer);
        }
    };

    return { createOffer };
};

export default usePeerConnection;

 

6. SIP 설정

SIP서버와 연결하기 위해 필요한 설정 정의.

// src/sipConfig.ts
export const sipConfig = {
    uri: 'sip:your_sip_username@your_sip_server',
    password: 'your_sip_password',
    wsServers: 'wss://your_sip_server:8089/ws',
    display_name: 'Your Display Name'
};

 

7. SIP 초기화

SIP UA(User Agent)를 초기화하고 전화 기능 설정

// src/hooks/useSip.ts

import { useEffect, useRef } from 'react';
import JsSIP from 'jssip';
import { sipConfig } from '../sipConfig';

const useSip = () => {
    const uaRef = useRef<JsSIP.UA | null>(null);

    useEffect(() => {
        const socket = new JsSIP.WebSocketInterface(sipConfig.wsServers);
        const configuration = {
            sockets: [socket],
            uri: sipConfig.uri,
            password: sipConfig.password,
            display_name: sipConfig.display_name,
        };

        uaRef.current = new JsSIP.UA(configuration);
        uaRef.current.start();

        return () => {
            uaRef.current?.stop();
        };
    }, []);

    const makeCall = (target: string) => {
        if (uaRef.current) {
            const eventHandlers = {
                progress: () => {
                    console.log('call is in progress');
                },
                failed: () => {
                    console.log('call failed');
                },
                ended: () => {
                    console.log('call ended');
                },
                confirmed: () => {
                    console.log('call confirmed');
                },
            };

            const options = {
                eventHandlers,
                mediaConstraints: { audio: true, video: false },
            };

            uaRef.current.call(target, options);
        }
    };

    return { makeCall };
};

export default useSip;

 

6. 컴포넌트 설정

// src/App.tsx
import React, { useRef } from 'react';
import useMediaStream from './hooks/useMediaStream';
import usePeerConnection from './hooks/usePeerConnection';

const App: React.FC = () => {
    const localVideoRef = useRef<HTMLVideoElement | null>(null);
    const remoteVideoRef = useRef<HTMLVideoElement | null>(null);
    const localStream = useMediaStream();
    const { createOffer } = usePeerConnection(localStream);

    if (localStream && localVideoRef.current && !localVideoRef.current.srcObject) {
        localVideoRef.current.srcObject = localStream;
    }

    return (
        <div>
            <video ref={localVideoRef} autoPlay playsInline muted />
            <video ref={remoteVideoRef} autoPlay playsInline />
            <button onClick={createOffer}>Start Call</button>
        </div>
    );
};

export default App;

 

728x90

Jira?

기획자, 팀원, 검토자간의 협업을 도와주는 도구이다.

Jira를 통해서 개발해야하는 기능, 버그 목록 등을 작성하고, 담당 개발자를 할당하여 개발 상태 및 배포를 관리할 수 있다.

 

Jira 용어 알아가기

  • project: issue들의 집합으로 전체 하나의 프로젝트가 될 수도 있고, 팀 단위로 프로젝트를 구성할 수 있다.
    프로젝트에서는 프로젝트 설정, 이슈 우선순위, 버전 관리 등을 할 수 있다.
  • issue: 프로젝트에서 수행할 업무 리스트에서 각 수행해야할 업무가 이슈이다.
    이슈는 고유 ID, 상태, 우선순위, 담당자, 기간 등의 정보를 가지며, 프로젝트에서 필요한 작업, 버그, 요구사항들이 될 수 있다.
  • board: 이슈들을 시각적으로 관리하는 공간이다.
  • epic: 큰 작업단위, 여러 이슈를 의미한다.
  • sprint: 일정 기간 동안의 작업 주기
  • backlog: 아직 스프린트에 할당되지 않은 이슈들의 목록
  • workflow: 이슈의 상태 변화를 나타내는 프로세스 (ex] To Do -> In Progress -> Done)

 

Jira시작하기

1. Project 생성

 

 

2. SCRUM BOARD 생성

  • SCRUM BOARD
    • 백로그를 스프린트 단위로 보여준다.
  •  KANBAN BOARD
    •  전체 백로그를 보여준다.

 

3. Issue 생성하기

 

3-1. Issue Type

  1. Epic : 큰 단위의 업무 ( User Story, Task 등을 묶은 단위 )
  2. User Story : 최종 고객에게 가치를 제공하는 기능
    • 작성 방법 : "I as WHO want to do WHAT, so that WHY"
    • User Story의 크기는 sprint내에 완료 가능한 단위로 분할 필요
    • ex) 사용자 관리 개발
  3. Task : User Story외의 기술적, 관리적 업무
    • ex) 설계, 서버 설치, 클라우드 도입 등
  4. Sub-Task : Story, Task를 더 작은 단위로 나눈 업무
    • 즉, 모든 Sub-Task가 끝나야 해당 업무 종료
    • ex) 사용자 관리(UI) 개발, 사용자관리(Service) 개발

https://pmcircle.wordpress.com/2015/07/30/confused-about-epic-story-task-and-sub-tasks/

 

 

참고: https://medium.com/dtevangelist/devops-jira%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%ED%98%91%EC%97%85-1%EB%B6%80-63c71489f21d

 

 

 

728x90

+ Recent posts