Kakao i Connect Live::Kakao i Connect Live 2.0::개발자 가이드::Android

페이지 이동경로

Android SDK 개발자 가이드

Android 버전의 카카오 i 커넥트 라이브 SDK 2.0은 안드로이드 앱에서 카카오 i 커넥트 라이브 서비스의 개발을 지원하는 Kotlin 라이브러리이며, Java 인터페이스도 제공합니다. SDK에서 제공하는 메서드와 이벤트를 활용하여 화상과 음성을 교환하는 실시간 스트리밍 서비스를 쉽게 만들 수 있습니다.
SDK 개발 순서는 크게 다음으로 구분할 수 있으며, 이 과정에서 사용되는 주요 메서드는 signIn(인증), createLocalMedia(로컬미디어생성), createRoom(Room 생성), connect(Room 접속), publish(로컬 미디어 공유), subscribe(리모트 미디어 구독)입니다. 이때 사용되는 이벤트는 connected, remoteVideoPublished입니다.
SDK에서 제공하는 메서드에 대한 자세한 설명은 API 레퍼런스 > Android 문서를 참고하시기 바랍니다.

Android SDK 개발자 가이드 그림Android SDK

주요 클래스 간 다이어그램

주요 클래스 간 다이어그램 그림주요 클래스 간 다이어그램

주요 클래스
클래스 설명
ConnectLive 카카오 i 커넥트 라이브 SDK 2.0의 최상위 클래스
- 인증, Room 생성, 미디어 생성을 담당
Room 스트리밍 서비스의 연결 단위 그룹을 나누는 개념의 클래스이며, 스트리밍 연결 및 기타 정보를 관리
Participant 라이브 스트리밍 서비스의 채팅방에 참여한 참여자
- LocalParticipant(로컬 참여자, 나 자신)와 RemoteParticipant(리모트 참여자, 리모트 참여자(Remote Participant))로 구분됨
Content 미디어의 기본 인터페이스
EventsCallback Room에서 발생하는 이벤트를 처리하기 위한 Callback
AudioHelper 오디오 포커스 및 장치 우선권을 제어하는 유틸리티 모듈

최소 개발 환경

Android SDK를 사용하기 위해서 아래의 환경을 요구합니다.

  • Android OS: 7.0(API 24, Nougat) 또는 그 이상
  • Kotlin: 1.6 이상 (또는 Java 1.8 이상)

사전 작업

카카오 i 커넥트 라이브 SDK 2.0을 사용하여 실시간 스트리밍 서비스를 개발하기 전, 다음의 사전 작업을 수행해야 합니다.

서비스 인증 정보 발급받기

카카오 i 커넥트 라이브 SDK 2.0을 사용하기 위해서는 고객사에서 선정한 인증 방식에 따라 카카오 i 커넥트 라이브 콘솔에서 서비스 인증 정보를 발급받아야 합니다.
SDK 기본 인증 방식인 커넥트 라이브 내부 인증 방식의 경우, 콘솔에서 서비스 ID(serviceId)서비스 시크릿(serviceSecret)을 발급받아야 합니다. 이 정보는 프로젝트 생성 시 자동 생성되며, 서비스 (앱)별로 구분되어 사용량 측정 및 과금의 기준이 됩니다. 따라서 하나 이상의 애플리케이션을 만들 경우에는 앱의 개수만큼 서비스 ID와 서비스 시크릿을 각각 발급받아야 합니다. 서비스 인증 정보를 발급받는 방법은 다음과 같습니다.
고급 인증 방식인 서비스 자체 인증 방식의 경우, 콘솔에서 서비스 ID(serviceId)를 발급받아야 합니다. 각 인증 방식 별 자세한 인증 프로세스는 인증 및 키 처리 문서를 참고하시기 바랍니다.

인증 방식 구분
인증 방식 구분 설명
기본 인증 방식: 커넥트 라이브 내부 인증 카카오 i 커넥트 라이브 SDK 2.0의 기본 인증 방식
- 콘솔에서 서비스 ID(serviceId)서비스 시크릿(serviceSecret) 발급 필요
- SDK 기본 인증 방식으로 별도의 서버 및 개발 작업이 필요 없음
- 자세한 설명은 서비스 인증 정보 발급하기 참고
고급 인증 방식: 서비스 자체 인증 최종 사용자에게 신원 확인용 토큰을 부여하고, 권한을 부여하는 서비스 자체 인증 방식
- 콘솔에서 서비스 ID(serviceId) 발급 필요
- 수준 높은 보안 레벨을 충족하며, 별도의 서버 및 개발 작업 필요
- 자세한 설명은서비스 인증 정보 발급하기 참고
주의
serviceId와 serviceSecret 정보가 외부로 유출될 경우에는 해킹 등 악용의 소지가 발생할 수 있으므로 코드 저장소 등에 노출되지 않도록 주의하시기 바랍니다.
안내
카카오 i 커넥트 라이브 콘솔에서는 사용자 인증 정보 관리, 워크스페이스 관리, 멤버 초대 등의 기능을 제공합니다. 콘솔 사용과 관련한 자세한 설명은 부록. 카카오 i 커넥트 라이브 콘솔 문서를 참고하시기 바랍니다.

Android Studio 설정하기

Android 버전의 카카오 i 커넥트 라이브 SDK 2.0을 설치하기 위해서는 Android Studio 프로젝트에서 Gradle 설정과 Manifest 설정을 완료해야 합니다

Gradle 설정하기

  1. Android Studio를 최신 버전으로 업데이트합니다.

  2. Android Studio > New Project 메뉴에서 신규 프로젝트를 생성합니다.

  3. gradle 설정에 ‘카카오 i 커넥트 라이브 SDK 2.0’의 의존성을 추가합니다.

    • 의존성 추가

    프로젝트에 종속 항목을 추가하려면 build.gradle파일의 dependencies블록에 implementation과 같은 종속 항목 구성을 지정합니다.

    코드예제의존성 추가 Syntax

    apply plugin: 'com.android.application'
    
    android { ... }
    
    dependencies {
        // Dependency on a remote binary
        implementation 'com.kakaoenterprise:icl2:2.+'
    }
    

    • 원격 저장소 추가

    종속 항목이 로컬 라이브러리나 파일 트리가 아닌 경우 Gradle은build.gradle파일의 repositories블록에서 지정된 온라인 저장소에서 파일을 찾습니다. 각 저장소를 나열하는 순서에 따라 Gradle이 각 프로젝트 종속 항목의 저장소를 검색하는 순서가 결정됩니다. 예를 들어 종속 항목을 저장소 A와 B에서 다운로드할 수 있고 A를 먼저 나열한 경우 Gradle은 저장소 A에서 종속 항목을 다운로드합니다.
    기본적으로 새 Android 스튜디오 프로젝트에서는 아래와 같이 Google Maven 저장소와 JCenter를 프로젝트의 최상위 수준build.gradle파일의 저장소 위치로 지정합니다.

    코드예제원격 저장소 추가 Syntax

    repositories {
        google()
        jcenter()
        maven { url "https://icl.jfrog.io/artifactory/kakaoenterprise" }
    }
    

  4. 본 가이드의 예제는 View Binding을 사용하고 있으며, build.gradle설정은 다음과 같습니다.

    코드예제View Binding Syntax

    android {
        defaultConfig{
    			...
    		}
    		...
    		
    		buildFeatures{
    				viewBinding true
    		}
    }
    

Manifest 설정하기

사용자 권한을 획득하기 위해서 Android Manifest를 업데이트합니다.

  1. Project/…/AndroidManifest.xml 파일을 엽니다.

  2. 다음 표. Manifest 권한 획득을 참고하여, 필요한 퍼미션을 업데이트합니다.

    • SDK는 기본적으로 런타임 권한 요청이 필요한 2가지(RECORD_AUDIO, CAMERA)를 포함해서 몇 가지 권한이 AndroidManifest.xml에 등록되어 있습니다.
    Manifest 권한 획득
    파라미터 타입 필수 여부 설명
    INTERNET 필수 normal 네트워크 통신을 위해 필요
    ACCESS_NETWORK_STATE 필수 normal 네트워크 상태 확인을 위해 필요
    FOREGROUND_SERVICE 선택 normal 화면공유 목적의 MediaProjection을 위해 필요
    MODIFY_AUDIO_SETTINGS 선택 normal 오디오 장치 관리를 위해 필요
    RECORD_AUDIO 필수 dangerous 로컬 오디오 전송 시 필요
    CAMERA 필수 dangerous 로컬 카메라 전송 시 필요

서비스 개발 순서

카카오 i 커넥트 라이브 SDK 2.0을 사용하여 간단한 실시간 화상회의 서비스를 구현하는 개발 순서는 다음과 같습니다. 서비스 개발은 사전 작업을 모두 완료해야 진행할 수 있습니다.

안내
카카오 i 커넥트 라이브 서비스에서 Local Participant(로컬 참여자)는 나 자신을 의미하며, Remote Participant(리모트 참여자)는 Room의 다른 참여자, 즉 리모트 참여자(Remote Participant)을 의미합니다.

예제 시나리오

본 문서에서 다루는 개발 예제는 Githubsimple 프로젝트를 기준으로 하며, 개발 시나리오는 다음과 같습니다.

예제 시나리오 그림예제 시나리오

  1. 앱 시작시 로컬카메라를 사용해 프리뷰를 보여줍니다.
  2. [JOIN] 버튼 터치 시 설정한 roomId에 해당하는 Room으로 접속합니다.
  3. Remote Participant(리모트 참여자)가 동일 roomId로 동일 Room에 접속하면 서로의 비디오와 오디오를 시청합니다.
  4. [CLOSE] 버튼 터치 시 연결을 끊고 앱을 종료합니다.

Step 1. SDK 초기화하기

Android 버전의 Kakao i Connect Live SDK 2.0을 초기화합니다. 모든 메서드를 호출하기 전 반드시 init() 메서드를 호출해야 합니다.

코드예제SDK 초기화하기 Syntax

    ConnectLive.init(this)

Step 2. 서비스 인증하기

콘솔에서 발급받은 서비스 인증 정보를 signIn() 메서드의 인자로 전달하여 서비스를 인증합니다. SDK 인증 방식은 커넥트 라이브 내부 인증과 서비스 자체 인증으로 구분됩니다. 각 인증 방식에 대한 자세한 설명은 signIn(카카오 i 커넥트 라이브 내부 인증)signIn(서비스 자체 인증)을 참고하시기 바랍니다.

코드예제커넥트 라이브 내부 인증 Syntax

    // 커넥트 라이브 내부 인증
    ConnectLive.signIn {
                serviceId = "ICLEXMPLPUBL"
                servicSecret = "YOUR0SRVC0SECRET"
            }

코드예제서비스 자체 인증 Syntax

    // 서비스 자체 인증
    ConnectLive.signIn {
        endpoint = "https://icl2-provisioning-ap2.k9ertc.io/api/rpc"
        serviceId = "ICLEXMPLPUBL"
        token = "YOUR_SERVICE_TOKEN"

        errorHandler = ErrorHandler { code, message, isFatal ->
            // 에러 처리
        }
    }

안내
인증 방식 별 인증 프로세스와 키 처리에 대한 자세한 설명은 인증 및 키 처리 문서를 참고하시기 바랍니다.

Step 3. 권한 확인 및 로컬카메라 렌더링하기

디바이스 권한을 확인하고 로컬 카메라를 생성하여 바인딩하는 방법은 다음과 같습니다.

  1. Activity Result API의 registerForActivityResult()를 활용하여 권한 확인 후, Local camera를 생성하고 local(VideoRenderer) 뷰에 bind합니다.

    코드예제권한 확인 및 로컬카메라 렌더링 1단계 Syntax

    private lateinit var binding: ActivityMainBinding
    private var camera: LocalCamera? = null
    
    private val requestPermissionForActivateMedia =
            registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
                result[Manifest.permission.CAMERA]?.let { cameraGranted ->
                    if (cameraGranted && camera == null) {
                        camera = ConnectLive.createLocalCamera().apply { start() }
                        binding.local.bind(camera)
                    }
                }
            }
    

  2. ActivityResultLauncher 클래스 launch 시 Manifest.permission.CAMERAManifest.permission.RECORD_AUDIO를 주입합니다.

    코드예제권한 확인 및 로컬카메라 렌더링 2단계 Syntax

    requestPermissionForActivateMedia.launch(
                arrayOf(
                    Manifest.permission.CAMERA,
                    Manifest.permission.RECORD_AUDIO
                )
            )
    

Step 4. 화면(View) 구성하기

SDK에서 제공하는 VideoRenderer를 사용하여 내 카메라를 렌더링하는 local( VideoRenderer)과 리모트 참여자의 영상을 렌더링하는 remote(VideoRenderer)를 생성합니다. 예제에서는 Room에 접속과 종료 트리거링을 위한 Button을 포함합니다.

코드예제화면(View) 구성하기 Syntax

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <io.kakaoi.connectlive.view.VideoRenderer
        android:id="@+id/local"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="9:16"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/btn_action"/>

    <io.kakaoi.connectlive.view.VideoRenderer
        android:id="@+id/remote"
        android:layout_width="200dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        app:layout_constraintDimensionRatio="9:16"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toTopOf="@id/btn_action"/>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/btn_action"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="join"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

위 예제에서는 viewBinding을 사용하였습니다. viewBinding 설정은 build.gradle(:simple)에서 확인하시기 바랍니다.

코드예제viewBinding 설정 Syntax

    buildFeatures{
        viewBinding true
    }

화면 및 버튼 구성 예제 그림화면 및 버튼 구성 예제

Step 5. 오디오 포커스 요청하기

SDK에서 오디오를 관리하기 위해 AudioHelper 클래스에 오디오 포커스를 요청합니다

코드예제오디오 포커스 요청하기 Syntax

AudioHelper.acquireFocus(context = this)

앱에서 카카오 i 커넥트 라이브 SDK 2.0의 사용 시나리오 종료 시, releaseFocus() 메서드를 통해 오디오 포커스 요청을 취소해야 합니다.

코드예제오디오 포커스 요청 취소 Syntax

override fun onDestroy() {
			// ...
      AudioHelper.releaseFocus()
}

Step 6. Room 객체 생성 및 Events 처리하기

리모트 참여자(Remote Participant)와 통신하기 위해서는 같은 Room에 들어가야 하며, 이를 위해 Room 객체를 생성해야 합니다. Room은 서비스에 따라 채팅방, 화상회의실 등 참여자들이 서비스를 이용하기 위해 입장하는 공간입니다. 자세한 설명은 createRoom()을 참고하시기 바랍니다.

코드예제Room 객체 생성 Syntax

room = ConnectLive.createRoom(events = OnEventListener())

Room을 생성할 때 Events를 등록해야 하며, 해당 샘플에서는 다음과 같이 작성합니다. Room에서 발생하는 다양한 이벤트의 처리는 Room.Events를 참고하시기 바랍니다.

코드예제Events 등록 Syntax

private lateinit var binding: ActivityMainBinding
private var localVideo: LocalVideo? = null

private inner class OnEventListener : EventsCallback {
        override fun onConnecting(progress: Float) {
            // 접속중...
        }

        override fun onConnected(participants: List<RemoteParticipant>) {
            // 해당 Room 접속 완료
			// 기존에 참여중이던 사람들의 목록을 받습니다.
            // 예제에서는 처음 들어는 비디오만 bind 하여 확인 합니다.
            if (participants.isNotEmpty()) {
                val remoteVideo = participants.flatMap { it.videos.values }.first()
                binding.remote.bind(remoteVideo)
            }

			// 버튼의 문구를 변경합니다.
            binding.btnAction.text = "close"
        }

        override fun onDisconnected(reason: DisconnectedReason) {
            finish()
        }

        override fun onError(code: Int, message: String, isFatal: Boolean) {
            val errorMessage = "code: $code, message: $message, isFatal: $isFatal"
            Log.d("onError", errorMessage)
            if (isFatal)
                finish()
        }

        override fun onLocalVideoPublished(video: LocalVideo) {
			// 나의 video가 publish 되었을때 불리며, 내 video를 local에 렌더링
            localVideo = video
            binding.local.bind(localVideo)
        }

        override fun onRemoteVideoPublished(participant: RemoteParticipant, video: RemoteVideo) {
            // 내가 참여 후 published 된 다른사람의 video를 VideoRenderer 에 bind
            binding.remote.bind(video)
        }

        override fun onRemoteVideoUnpublished(participant: RemoteParticipant, video: RemoteVideo) {
            // 다른 사람이 퇴장 혹은 video를 unPublish 했을때 unbind
            binding.remote.unbind()
        }
    }

Step 7. Room 접속하기

다음은 Button의 문구가 “join”일 때 클릭 이벤트가 들어오면 Room에 접속하는 샘플 코드입니다. Room에 접속할 때는 connect()메서드를 사용하며, Room의 고유한 ID 값인 roomId를 인자로 사용합니다. 샘플에는 roomId 값이 비어 있어 해당 값을 기입해야 합니다. roomId는 영문 대소문자, 숫자, -으로 구성이 가능하며, 길이 제한은 32자입니다.

주의
샘플에는 roomId 값이 비어 있으니, 해당 값을 기입해야 합니다.

  • roomId는 영문 대소문자, 숫자, -으로 구성이 가능하며, 길이 제한은 32자입니다.
  • roomId 값이 허용조건에 해당하지 않는 경우 Join 버튼을 눌렀을때 앱이 종료됩니다.

코드예제Room 접속하기 Syntax

private lateinit var binding: ActivityMainBinding
private lateinit var room: Room
private var camera: LocalCamera? = null

binding.btnAction.setOnClickListener {
            if ((it as Button).text == "join") {
                // 로컬 프리뷰카메라 정지및 해제
                camera?.stop()
                camera?.dispose()

                // 해당 roomId로 접속
                room.connect(roomId = "roomId를 넣어주세요.")
                val localMedia = ConnectLive.createLocalMedia().apply {
                    video?.isEnabled = true
                    audio?.isEnabled = true
                }

                // 내 localMedia publish
                room.publish(localMedia)
            }
        }

자신의 화면을 Room에 게시하기

참여자 자신의 스크린 화면을 Room에 게시하기 위해서는, createLocalScreen()을 통해 LocalScreen 객체를 생성하고 게시하면 됩니다. 자세한 내용은 createLocalScreen()을 참고하시기 바랍니다.

코드예제자신의 화면을 Room에 게시하기 Syntax

val localScreen = ConnectLive.createLocalScreen(data, onStop = { })

publish(localScreen)

Step 8. 로컬 미디어 처리하기

createLocalMedia() 메서드를 사용하여 참여자 자신의 로컬 마이크와 카메라에 접근할 수 있습니다. 이를 통해 실시간 스트리밍 서비스에 이용할 수 있는 LocalMedia 객체가 생성됩니다. LocalMedia는 audio(오디오)와 video(비디오) 객체를 가지고 있으며, 서비스에 맞게 객체를 설정할 수 있습니다.

코드예제createLocalMedia() 메서드 Syntax

private lateinit var room: Room

val localMedia = ConnectLive.createLocalMedia().apply {
					video?.isEnabled = true
                    audio?.isEnabled = true
                }                
room.publish(localMedia)

게시 중인 video(비디오)를 내가 원하는 Step 3. 권한 확인 및 로컬카메라 렌더링하기에서 선언한 local view(VideoRenderer)에 바인딩(binding)합니다.

코드예제local view(VideoRenderer)에 bind Syntax

private lateinit var binding: ActivityMainBinding

private inner class OnEventListener : EventsCallback {
				...
        override fun onLocalVideoPublished(video: LocalVideo) {
			// 나의 video가 publish 되었을때 불리며, 내 video를 local에 렌더링합니다.
            localVideo = video
            binding.local.bind(localVideo)
        }
				...
    }

Step 9. 리모트 미디어 처리하기

Room에 성공적으로 접속하면 onConnected 이벤트가 호출됩니다. onConnected에서는 기존에 참여 중인 모든 참여자의 정보(RemoteParticipant)를 받을 수 있습니다. 이 정보에서 RemoteVideo를 꺼내 Step 4. 화면(View) 구성하기에서 선언한 remote view(VideoRenderer)에 바인딩(binding)하면 리모트 참여자(Remote Participant)의 리모트 미디어(Remote Media)를 수신할 수 있습니다.

코드예제리모트 미디어 처리하기 Syntax

private lateinit var binding: ActivityMainBinding

private inner class OnEventListener : EventsCallback {
				...
        override fun onConnected(participants: List<RemoteParticipant>) {
            // 해당 Room 접속 완료
			// 기존에 참여중이던 사람들의 목록을 받습니다.
            // 예제에서는 처음 들어는 비디오만 bind하여 확인합니다.
            if (participants.isNotEmpty()) {
                val remoteVideo = participants.flatMap { it.videos.values }.first()
                binding.remote.bind(remoteVideo)
            }
        }
    }

안내
위 예제에서는 단 한 명의 리모트 참여자(Remote Participant)만 볼 수 있도록 구현이 되어있으며, 여러 명의 참여자가 있을 때 최초 한 명만 Rendering 되게 됩니다. remote view(VideoRenderer) 사용 시, 이 점을 유의하시기 바랍니다.

만약 리모트 참여자가 로컬 참여자(나 자신)보다 늦게 참여한 경우에는 onRemoteVideoPublished의 이벤트를 확인하여, Step 4. 화면(View) 구성하기에서 선언한 remote view(VideoRenderer)에 바인딩(binding)하여 리모트 참여자(Remote Participant)의 미디어를 수신할 수 있습니다.

코드예제onRemoteVideoPublished 이벤트 Syntax

private lateinit var binding: ActivityMainBinding

private inner class OnEventListener : EventsCallback {
				...
        override fun onRemoteVideoPublished(participant: RemoteParticipant, video: RemoteVideo) {
            // 내가 참여후 published 된 다른사람의 video를 VideoRenderer에 bind
            binding.remote.bind(video)
        }
				...
    }

리모트 참여자가 Room에서 퇴장 또는 video(비디오)의 게시를 취소한 경우에는 onRemoteVideoUnpublished 이벤트가 발생합니다. 해당 이벤트에서 unbind 하면 렌더링을 취소할 수 있습니다.

코드예제onRemoteVideoUnpublished 이벤트 Syntax

private lateinit var binding: ActivityMainBinding

private inner class OnEventListener : EventsCallback {
				...
        override fun onRemoteVideoUnpublished(participant: RemoteParticipant, video: RemoteVideo) {
            binding.remote.unbind()
        }
				...
    }

Step 10. Room 접속 해제하기

다음은 Button의 문구가 “join”이 아닌 경우 접속 해제를 하는 코드입니다.
샘플에서는 ConnectLive.createRoom()으로 생성된 Room 객체에 disconnect() 함수를 호출하여 Room 접속을 종료합니다.

코드예제Room 접속 해제하기 Syntax

    binding.btnAction.setOnClickListener {
                if ((it as MaterialButton).text == "join") {
                    ...
                } else {
                    // 연결해제
                    room.disconnect()
                }
            }

주요 이벤트

Android 버전의 카카오 i 커넥트 라이브 SDK 2.0의 주요 이벤트는 다음과 같습니다. 주요 이벤트 외 모든 이벤트 정보는 Room.Events 문서를 참고하시기 바랍니다.

onConnected

onConnected는 참여자가 Room과의 연결이 완료되었을 때 발생하는 이벤트입니다. 해당 이벤트는 이미 Room에 참여하고 있는 Remote Participant(리모트 참여자) 목록을 인자로 전달합니다. RemoteVideo들을 VideoRenderer에 바인드(bind)시키면 영상이 렌더링됩니다.

코드예제onConnected Syntax

    private val remoteVideos = MutableLiveData(emptyList<RemoteVideo>())

    private inner class OnEventListener : EventsCallback {
                    ...
            override fun onConnected(participants: List<RemoteParticipant>) {
                remoteVideos.value = participants.flatMap { it.videos.values }
            }
                    ...
        }

onParticipantEntered

onParticipantEntered는 새로운 Remote Participant(리모트 참여자)가 Room에 입장했을 때 호출됩니다. 이곳에서 새로운 Remote Participant(리모트 참여자) 목록을 만들어 화면에 표시할 수 있습니다.

코드예제onParticipantEntered Syntax

    private inner class OnEventListener : EventsCallback {
                    ...
            override fun onParticipantEntered(participant: RemoteParticipant) {
                // participant를 참여자 목록에 추가
            }
                    ...
        }

onParticipantLeft

Remote Participant(리모트 참여자)가 Room에서 퇴장하여 Room과 연결이 끊겼을 때 호출됩니다. 해당 이벤트는 Remote Participant(리모트 참여자) 정상 종료와 비정상 종료를 구분하지 않습니다. 정상 종료의 경우 이벤트는 바로 호출이 되며 비정상 종료의 경우 수 초 후에 이벤트가 호출됩니다. 이곳에서 기존 Remote Participant(리모트 참여자) 목록에서 해당 참여자를 제거할 수 있습니다.

코드예제onParticipantLeft Syntax

    private inner class OnEventListener : EventsCallback {
                    ...
            override fun onParticipantLeft(participant: RemoteParticipant) {
                // participant를 참여자 목록에서 제거
            }
                    ...
        }

onRemoteVideoPublished

Remote Participant(리모트 참여자)가 비디오를 공유했을 때 호출됩니다. 해당 이벤트는 remoteVideo와 remoteParticipant 두 객체를 인자로 전달받아, 어떤 비디오를 어떤 Remote Participant(리모트 참여자가) 공유했는지 알 수 있으며, remoteVideo.owner 를 통해 공유자를 확인할 수 있습니다.

코드예제onRemoteVideoPublished Syntax

    private val remoteVideos = MutableLiveData(emptyList<RemoteVideo>())

    private inner class OnEventListener : EventsCallback {
                    ...
            override fun onRemoteVideoPublished(participant: RemoteParticipant, video: RemoteVideo) {
                remoteVideos.value = remoteVideos.value.orEmpty() + video
            }
                    ...
        }

onRemoteVideoUnpublished

Remote Participant(리모트 참여자)가 비디오를 공유 해제하면 호출됩니다.

코드예제onRemoteVideoUnpublished Syntax

    private val remoteVideos = MutableLiveData(emptyList<RemoteVideo>())

    private inner class OnEventListener : EventsCallback {
                    ...
            override fun onRemoteVideoUnpublished(participant: RemoteParticipant, video: RemoteVideo) {
                remoteVideos.value = remoteVideos.value.orEmpty() - video
            }
                    ...
        }

에러 처리

Android 버전의 카카오 i 커넥트 라이브 SDK 2.0의 에러에는 서버로부터 발생한 서버 에러(Server Error)와 클라이언트에서 비정상 접근으로 인한 에러(throws)가 존재합니다. 서버 에러는 ErrorHandler와 Room.Events.onError 이벤트로 처리할 수 있습니다.

에러 처리
에러 타입 설명
서버 에러
- 서버에서 발생한 에러 코드와 메시지를 담고 있으며, error code는 음수 다섯 자릿수로 표현
- 서버 에러는 ErrorHandler 또는 Room.Events.onError 이벤트로 처리
ErrorHandler 인증 체계와 관련된 에러를 처리
- 서버의 응답이나 사전의 정의한 오류 코드를 내보냄
Room.Events.onError Room 생성 후 발생하는 클라이언트 에러를 처리
클라이언트 에러(throws) 클라이언트 에러
- 비정상 접근으로 인한 SDK 발생 Throw이며, 메시지에는 에러 코드가 포함됨

서버 에러 처리

서버 에러는 ErrorHandler 또는 Room.Events.onError 이벤트로 처리합니다.

ErrorHandler

ConnectLive.signIn() 메서드에서 ErrorHandler를 정의하여, 인증 체계와 관련된 에러를 확인할 수 있습니다.

코드예제ErrorHandler Syntax

    ConnectLive.signIn {
                serviceId = "ICLEXMPLPUBL"
                serviceSecret = "YOUR0SRVC0SECRET"
                errorHandler = ErrorHandler { code, message, isFatal ->
                    val errorMessage = "Error(ConnectLive): code: $code / message: $message / isFatal: $isFatal"
                    Log.e("TAG", errorMessage)
                    if (isFatal)
                        finish()
                }
            }

Room.Events.onError

Room에 연결부터 종료까지, 해당 객체를 사용하면서 발생한 에러를 확인할 수 있습니다.

코드예제Room.Events.onError Syntax

    private inner class OnEventListener : EventsCallback {
                    ...
            override fun onError(code: Int, message: String, isFatal: Boolean) {
                val errorMessage = "Error(ConnectLive): code: $code / message: $message / isFatal: $isFatal"
                    Log.e("TAG", errorMessage)
                    if (isFatal)
                        finish()
            }
                    ...
        }

클라이언트 에러 처리

클라이언트 에러로 비정상 접근으로 인해 SDK에서 Throw를 발생시키며, 메시지에는 에러 코드가 포함됩니다

비정상 접근으로 발생한 Throw
Throws 설명
IllegalStateException 다음의 경우를 포함
- 인증을 수행하는 signIn(카카오 i 커넥트 라이브 내부 인증) 메서드를 호출하지 않은 상태에서 Room에 접근한 경우
- createRoom 당시 로그인이 유효하지 않음
- 기존 로그인이 유효한 상태로 재인증이 필요 없음
- 장치 접근 권한(CAMERA, RECORD_AUDIO)이 확보되지 않음
IllegalArgumentException 다음의 경우를 포함
- signIn 중 필요한 정보가 누락되거나 불필요한 정보가 존재하는 경우
- 스트림의 상태가 video/audio 중 하나에 포함되지 않는 경우
RuntimeException Local Video 또는 Audio 생성에 실패함

에러 코드

전체 에러 코드는 다음과 같습니다.

에러 코드 전체 목록
Code Message 설명
1103 인증을 위한 서비스 정보가 입력되지 않았습니다. signIn() 메서드 사용 시 인증정보가 모두 입력되지 않았을 경우
1106 Room 생성 전 인증이 필요합니다. creteRoom() 메서드 사용 당시 미인증 상태인 경우
1208 로컬 카메라 생성에 실패했습니다. 비디오 트랙을 얻기 위해 createLocalMedia() 메서드를 호출하는 경우
1209 로컬 오디오 생성에 실패했습니다. 오디오 트랙을 얻기 위해 createLocalMedia() 메서드를 호출하는 경우
1210 이미 Focus가 존재합니다. AudioHelper의 포커스가 이미 존재한 경우이며, isFocusAcquired를 통해 미리 확인할 수 있음
1301 입력한 룸 id가 지원하지 않는 길이, 문자를 포함합니다.(32자 이하, 영문자/숫자/- 만 가능) connect() 메서드 호출 시 room id를 검증하지 못했을 때 발생할 수 있음
1326 비디오 구독을 위한 리시버를 할당받을 수 없습니다. video Receiver를 추가할 수 없는 경우
1361 비정상 스트림 정보가 존재합니다. subscribe() 메서드 호출 시 이미 구독 중인 비디오라면 발생할 수 있음
1362 이미 게시 중인 video입니다. 이미 게시된 video를 중복으로 게시할 경우
1363 이미 게시 중인 audio입니다. 이미 게시된 audio를 중복으로 게시할 경우
1401 PeerConnection 생성이 실패했습니다. connect() 메서드 호출 시 발생할 수 있음
1402 데이터 채널 생성이 실패했습니다. connect() 메서드 호출 시 발생할 수 있음
1439 송신 세션의 Offer, Answer 설정이 실패했습니다. 미디어를 Room에 송출 중 발생할 수 있음
1440 Description 설정에 실패했습니다. connect() 메서드 호출 시 발생할 수 있음
1442 스트림 추가 에러(native 원본 메시지) 스트림 추가 에러
1450 스트림 설정 변경에 실패했습니다. 스트림 설정 변경에 확인되지 않은 Participant가 있는 경우
1452 스트림 설정 요청이 실패했습니다. 이미 요청되었거나, 존재하지 않는 요청인 경우
1911 publish() 후 extraValue 변경은 불가합니다. publish() 메서드 호출 후, video 또는 audio의 extraValue를 수정한 경우
1912 통신 프로토콜 종료됨 통신 프로토콜이 종료된 상태에서 이벤트를 보내려는 경우
안내
클라이언트 관련 에러 코드 및 설명은 Error Code 문서를 참고하시기 바랍니다.
이 문서가 만족스러운 이유를 알려주세요.
이 문서에 아쉬운 점을 알려주세요.
평가해주셔서 감사합니다.

더 자세한 의견은 documentation@kakaoenterprise.com 으로 제보해주세요.