본문 바로가기

[unity] WebRTC 사용법

앤디가이 2022. 6. 7.

Unity WebRTC 튜토리얼 및 샘플을 토대로 Unity에서 어떤 개념으로 화면 공유가 되는 건지 연구해 보자.

Unity용 WebRTC 샘플 파일 설치 및 소개는 블로그 이전 편을 참고하면 좋다.

WebRTC 소개 및 설치 방법

 

[unity] WebRTC 소개 및 설치 방법

Unity WebRTC에 대한 설명과 WebRTC for unity 패키지 설치 방법에 대해 알아보자. 1. WebRTC 소개  - WebRTC는 Web-Realtime Communication의 약자로, 웹에서 실시간 커뮤니케이션할 수 있는 기술을 말한다.  -..

wonjuri.tistory.com

 

네트워크 관련 지식이 많지 않아. 해당 샘플 파일을 이해하는데 초기 어려움이 많았다.

서버 없이 네트워크처럼 화면, 영상, 음성이 공유되는 원리를 먼저 이해하고 WebRTC를 연구해보면 더 좋을 것 같다.

샘플로 제공해주는 PeerConnectionSampe.cs 튜토리얼을 따라 하기 식으로 접근하여, 개념을 이해해보고자 했다.

참고로 아래 코드에는 샘플에 나오는 테스트 버튼 관련 변수 및 내용은 제외하였다.(WebRTC 부분만 연구)

 

1. 네임스페이스 추가

 - Unity에서 WebRTC 사용시 아래와 같이 NameSpace를 추가해줘야 한다.

using UnityEngine;
using Unity.WebRTC;

 

2. Peer 선언 및 Delegate 선언

 - RTCPeerConnection 클래스 변수 pc1, pc2를 선언한다. 

   . WebRTC가 Peer to Peer 형태로 연결되는 개념이기 때문에 저렇게 두 pc의 연결을 위한 객체라고 보면 된다.

 - 각 Peer마다 DelegateOnIceCandidate Delegate를 선언한다.

   . WebRTC 코드를 보면 Candidate, ICE라는 단어가 많이 나온다. 개념을 조금 잡고 코드를 보면 이해하기 좀 더 수월하다.

   . Candidate : Stun 서버를 이용해 획득한 IP 주소 및 포트 정보 등의 연결 가능한 네트워크 주소들을 말한다.

   . ICE : 두 개의 단말이 P2P 연결되도록 도와주는 프레임워크이다.

   . 즉 해당 Delegate는 ICE 프레임워크를 통해서 두 개의 단말 네트워크 주소를 찾아주고, 연결 가능한 상태를 만들어 주는 역할이다.

 

 

 - 변수 코드는 아래를 참고하자.

private RTCPeerConnection _pc1, _pc2;
private List<RTCRtpSender> pc1Senders;
private MediaStream videoStream, receiveStream;
private DelegateOnIceConnectionChange pc1OnIceConnectionChange;
private DelegateOnIceConnectionChange pc2OnIceConnectionChange;
private DelegateOnIceCandidate pc1OnIceCandidate;
private DelegateOnIceCandidate pc2OnIceCandidate;
private DelegateOnTrack pc2Ontrack;
private DelegateOnNegotiationNeeded pc1OnNegotiationNeeded;
private bool videoUpdateStarted;

 

3. 초기화

 - Unity 기본 이벤트 함수인 Awake() 및 Start() 함수에서 초기화를 진행한다.

 - Awake()함수에서 WebRTC의 Initialize 함수를 통해 초기화해준다.

   . 초기화 시 텍스쳐 사이즈 제한을 매개변수로 넣어줄 수 있다.

 - Start() 함수에서 Delegate 할당 및 비디오 및 미디어 스트림 트랙 이벤트를 등록해준다.

private void Awake()
{
    //WebRTC 초기화.
    WebRTC.Initialize();
}

private void Start()
{
    pc1OnIceConnectionChange = state => { OnIceConnectionChange(_pc1, state); };
    pc2OnIceConnectionChange = state => { OnIceConnectionChange(_pc2, state); };
    pc1OnIceCandidate = candidate => { OnIceCandidate(_pc1, candidate); };
    pc2OnIceCandidate = candidate => { OnIceCandidate(_pc2, candidate); };
    pc2Ontrack = e =>
    {
        receiveStream.AddTrack(e.Track);
    };
    pc1OnNegotiationNeeded = () => { StartCoroutine(PeerNegotiationNeeded(_pc1)); };
}

 

4. 네트워크 통신 경로 등록

 - 통신하는 두 단말기의 프로토콜은 동일해야 한다.

 

 

 - AddIceCandidate() 함수를 통해 서로 단말에 대한 네트워크 정보를 추가해준다.

private void OnIceCandidate(RTCPeerConnection pc, RTCIceCandidate candidate)
{
    switch((ProtocolOption)dropDownProtocol.value)
    {
        case ProtocolOption.Default:
            break;
        case ProtocolOption.UDP:
            if (candidate.Protocol != RTCIceProtocol.Udp)
                return;
            break;
        case ProtocolOption.TCP:
            if (candidate.Protocol != RTCIceProtocol.Tcp)
                return;
            break;
    }

    GetOtherPc(pc).AddIceCandidate(candidate);
}

enum ProtocolOption
{
    Default,
    UDP,
    TCP
}

 

5. 시그널링

 - 두 단말 간에 스트림을 교환하기 위해서는 시그널링을 해줘야 한다.

  . 시그널링이란 WebRTC 통신에 사용할 프로토콜과 미디어 코덱, 데이터 전송 방법 등을 포함한 통신 규격을 교환하기 위해 두 단말 간 제어 정보를 교환하는 과정을 말한다.

 - 시그널링을 위해서 먼저 SDP(Session Descriptin protocol) 개념을 알아야 한다.

  . SDP : WebRTC에서 스트리밍 미디어의 해상도나 형식, 코덱 등의 멀티미디어 초기 인수를 설명하기 위해 채택한 프로토콜이다.

  . 예를 들어 피어가 미디어 스트림을 교환할 것을 원할 경우 아래와 같은 프로세스가 진행된다.

     1. 요청하면, 상대 피어로부터 응답이 오기를 기다린다. 

     2.  응답을 기다린 후 ICE 중에 최적의 경로를 결정하고 안정적인 경로를 찾는다.

     3. ICE 후보가 선택되면, 기본 IP 주소 , 포트 정보, 미디어 정보를 피어 간 합의를 완료한다.

 - Unity에서 샘플 코드를 보면 다음과 같다.

IEnumerator PeerNegotiationNeeded(RTCPeerConnection pc)
{
    var op = pc.CreateOffer();
    yield return op;

    if (!op.IsError)
    {
        if (pc.SignalingState != RTCSignalingState.Stable)
        {
            yield break;
        }

        yield return StartCoroutine(OnCreateOfferSuccess(pc, op.Desc));
    }
}
private IEnumerator OnCreateOfferSuccess(RTCPeerConnection pc, RTCSessionDescription desc)
{
    var op = pc.SetLocalDescription(ref desc);
    yield return op;

    if (!op.IsError)
    {
        OnSetLocalSuccess(pc);
    }
    else
    {
        var error = op.Error;
        OnSetSessionDescriptionError(ref error);
        yield break;
    }

    var otherPc = GetOtherPc(pc);
    var op2 = otherPc.SetRemoteDescription(ref desc);
    yield return op2;
    if (!op2.IsError)
    {
        OnSetRemoteSuccess(otherPc);
    }
    else
    {
        var error = op2.Error;
        OnSetSessionDescriptionError(ref error);
        yield break;
    }

    var op3 = otherPc.CreateAnswer();
    yield return op3;
    if (!op3.IsError)
    {
        yield return OnCreateAnswerSuccess(otherPc, op3.Desc);
    }
    else
    {
        OnCreateSessionDescriptionError(op3.Error);
    }
}

 

6. 데이터 송수신

 - 영상 공유의 경우 WebRTC.Update() 함수를 통해, 매 프레임 업데이트해준다.

private void AddTracks()
{
    foreach (var track in videoStream.GetTracks())
    {
        pc1Senders.Add(_pc1.AddTrack(track, videoStream));
    }

    if (WebRTCSettings.UseVideoCodec != null)
    {
        var codecs = new[] {WebRTCSettings.UseVideoCodec};
        foreach (var transceiver in _pc1.GetTransceivers())
        {
            if (pc1Senders.Contains(transceiver.Sender))
            {
                transceiver.SetCodecPreferences(codecs);
            }
        }
    }

    if (!videoUpdateStarted)
    {
        StartCoroutine(WebRTC.Update());
        videoUpdateStarted = true;
    }
}
receiveStream.OnAddTrack = e =>
{
    if (e.Track is VideoStreamTrack track)
    {
        track.OnVideoReceived += tex =>
        {
            receiveImage.texture = tex;
            receiveImage.color = Color.white;
        };
    }
};

 

7.  결과 화면

 - 왼쪽 화면(PC1)을 오른쪽 화면(PC2)으로 화면 공유가 진행된다.

 

 

 - CandidateId를 보면 저로 다른 두 개의 Peer가 연결된 걸 확인할 수 있다.

unity webrtc peerconnection
unity webrtc peerconnection

  - Unity window 메뉴 중 Analysis -> WebRTC Stats를 열어보면 연결된 Peer 정보를 확인할 수 있다.

WebRTC Stats
WebRTC Stats

 

메타버스 시대에 화상서비스를 위해서는 WebRTC는 필수인 영역 같다. 

지금은 간단히 알아본 WebRTC였지만, 프로젝트 기회가 된다면 좀 더 깊이 연구해보면 좋을 것 같다는 생각이 든다.

 

 

[참고]

1. Unity Web RTC Manual

2. WebRTC Org

3. WebRTC 설명 블로그

댓글