Android - WebRTC (1)

유의선·2024년 11월 21일

WebRTCPeer to Peer로 두 피어 간 영상, 음성, 데이터를 주고받는 통신 프로토콜이다.

두 피어는 서로의 멀티미디어 세션(Session Description Protocol) 을 주고 받고, 서로의 연결 정보(Ice Canditates) 를 주고 받아 연결을 확립한다.


구현에 필요한 요소

먼저 위에서 설명한 SDP와 Ice Candidates를 교환할 때 사용되는 Signaling Server가 필요하다.
두 정보를 교환할 때만 쓰이므로 비교적 자유롭게 구현이 가능하다고 생각된다.
본인은 Signaling Server를 AWS Iot MQTT를 사용해 구현하였다.

다음으로 STUN 서버라 불리는 서버가 필요하다.
두 Peer가 같은 네트워크에 있을 때에는 HOST 타입의 Ice Candidate를 사용해 별도의 서버 없이 구현 가능하지만, 다른 네트워크에 속해 있을때는 STUN 서버가 필요하다.
STUN 서버는 Google 같은 곳에서 무료로 지원하는 것들이 있으니 이를 사용하였다(stun:stun.l.google.com:19302).

마지막으로 TURN 서버가 있다.
TURN 서버는 STUN 서버를 사용해도 방화벽/NAT 등의 이유로 외부망과의 통신이 불가능 할 때 사용된다. 그럴때 TURN 서버는 직접 데이터를 중계하는 역할을 한다.
본인은 TURN 서버를 AWS EC2에 Coturn 서버를 구축하여 사용하였다.


WebRTC 라이브러리들

찾아본 바로는 안드로이드에서 WebRTC를 사용하는 방법은 두 가지 있다.

Ver 1.0.30039

https://github.com/ALEXGREENCH/google-webrtc
위 링크의 repository를 사용하면 1.0.30039 버전의 WebRTC 라이브러리를 사용할 수 있다.

settings.gradle.kts

pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
        // ----- 추가 코드 -----
        maven { url = uri("https://raw.githubusercontent.com/alexgreench/google-webrtc/master") }
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        // ----- 추가 코드 -----
        maven { url = uri("https://raw.githubusercontent.com/alexgreench/google-webrtc/master") }
    }
}

build.gradle.kts(Module :app)

dependencies {
    implementation("org.webrtc:google-webrtc:1.0.30039@aar")
}

GetStream

https://github.com/getstream/webrtc-android?tab=readme-ov-file
위 링크의 repository를 사용하면 지원이 끊기기 전 가장 최신 버전의 WebRTC 라이브러리를 사용할 수 있으며, 그외에도 제작자가 추가한 기능들을 사용할 수 있다.

build.gradle.kts(Module :app)

dependencies {
    implementation("io.getstream:stream-webrtc-android:1.1.3")
}

주요 클래스/함수

  • PeerConnectionFactory

    • PeerConnection, VideoSource, VideoTrack 등의 객체를 만들고 관리한다.

          public void createPeerConnectionFactory() {
          PeerConnectionFactory.InitializationOptions initializationOptions = PeerConnectionFactory
                  .InitializationOptions.builder(context)
                  .createInitializationOptions();
          PeerConnectionFactory.initialize(initializationOptions);
      
          DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory(
                  eglBase.getEglBaseContext(),  /* enableIntelVp8Encoder */true,  /* enableH264HighProfile */true);
          DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(eglBase.getEglBaseContext());
      
          peerConnectionFactory = PeerConnectionFactory.builder().setVideoEncoderFactory(defaultVideoEncoderFactory).setVideoDecoderFactory(defaultVideoDecoderFactory).createPeerConnectionFactory();
      
          Log.d(TAG, "PeerConnectionFactory 생성됨");
      }
          
          ...
          
          peerConnection = peerConnectionFactory.createPeerConnection(...);
      
      				videoCapturer = createVideoCapturer();
      				videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast());
      				localVideoTrack = peerConnectionFactory.createVideoTrack("100", videoSource);
  • PeerConnection

    • 두 피어 간 실시간 오디오, 비디오, 데이터 통신을 설정하고 관리하는 역할을 한다.

         PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(Collections.singletonList(new PeerConnection.IceServer("stun:stun.l.google.com:19302")));
          config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
      
          PeerConnection peerConnection = peerConnectionFactory.createPeerConnection(config, new PeerConnection.Observer(){...});
    • SDP를 사용하여 피어 간의 미디어 설정을 협상한다.

      // 다른 피어에게 전송할 오퍼 SDP 생성
      peerConnection.createOffer(new SdpObserver(){...}, new MediaConstraints());
      // 원격 피어의 오퍼에 대한 응답 SDP 생성
      peerConnection.createAnswer(new SdpObserver(){...}, new MediaConstraints());
      // 로컬 피어의 SDP 설정
      peerConnection.setLocalDescription(new SdpObserver(){...}, SessionDescription);
      // 원격 피어로부터 받은 SDP 설정
      peerConnection.setRemoteDescription(new SdpObserver(){...}, SessionDescription);
    • ICE 후보들을 수집하여 최적의 네트워크 경로를 선택한다.

      peerConnection.addIceCandidate(IceCandidate);
    • 비디오 트랙, 데이터 채널 등을 관리한다.

      dataChannel = peerConnection.createDataChannel("myDataChannel", dcInit);
      
      peerConnection.addTrack(localVideoTrack);
  • SessionDescription

    • 피어 간의 연결을 설정하는데 사용되는 중요한 객체. 세션의 미디어 설정을 정의하는 SDP (Session Description Protocol) 메시지를 포함한다.
    • 피어 간에 오퍼(Offer)와 응답(Answer) SDP를 주고 받음으로 두 피어 간 미디어 세션을 설정한다.
  • IceCandidate

    • 피어 간의 가능한 네트워크 경로를 나타낸다.
    • 피어 간의 연결을 최적화하기 위해 서로의 Ice Candidates를 교환하며, addIceCandidate() 메소드를 통해 추가한다.
  • RTCConfiguration

    • PeerConnection 객체를 만들 때 사용되는 설정 클래스. ICE 서버, 피어 간의 연결을 설정하는 데 필요한 다양한 옵션을 설정할 수 있다.
  • SurfaceViewRenderer

    • WebRTC 비디오 트랙에서 받은 비디오 프레임을 Android 장치의 화면에 그리는 역할을 한다.
      remoteVideoTrack.addSink(surfaceViewRenderer);

2개의 댓글

comment-user-thumbnail
2024년 12월 30일

저도 GetStream 쪽 레포받아서 돌려보는데, 아래와 같은 에러발생하면서 크래시 안나시나요?
(https://github.com/GetStream/webrtc-in-jetpack-compose)

No implementation found for long org.webrtc.SoftwareVideoDecoderFactory.nativeCreateDecoder(long, org.webrtc.VideoCodecInfo) (tried Java_org_webrtc_SoftwareVideoDecoderFactory_nativeCreateDecoder and Java_org_webrtc_SoftwareVideoDecoderFactory_nativeCreateDecoder__JLorg_webrtc_VideoCodecInfo_2) - is the library loaded, e.g. System.loadLibrary?

답글 달기
comment-user-thumbnail
2025년 3월 6일

안녕하세요 webrtc 관심이 많은 학생 입니당~~
깃허브 공유 가능하실까요?

답글 달기