Skip to content

Android SDK Integration Guide ​

1. Environment Requirements ​

ItemRequirement
Minimum Android versionminSdk 27 (Android 8.1, recommended)
Supported CPU architecturesarmeabi-v7a, arm64-v8a, x86, x86_64

To filter by architecture, configure abiFilters in the defaultConfig block of your app module's build.gradle file:

groovy
android {
    defaultConfig {
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }
    }
}

2. Import the AAR File ​

Copy webrtc-pull-stream-release.aar to the app/libs directory of your application module, then add the dependency in your build.gradle file:

groovy
dependencies {
    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
}

3. Declare Permissions ​

Declare the permissions required by the SDK in your AndroidManifest.xml file:

xml
<!-- Network permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Camera permission -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- Microphone permission -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

TIP

CAMERA and RECORD_AUDIO are dangerous permissions. On Android 6.0 and above, they must be requested at runtime.

4. Add PullStreamView to Your Layout ​

Add the PullStreamView widget to your layout XML:

xml
<com.yjz.pullstream.webrtc.render.PullStreamView
    android:id="@+id/pullStreamView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:maxStretchRatio="1.2"
    app:stretchEnabled="false"
    android:gravity="center"
/>

5. Initialize WebrtcClient ​

Required Parameters ​

  1. signalServerUrl: Signaling server URL
  2. roomId: Room ID
  3. Token: Business token
  4. turnServerUrl: TURN server URL

Initialization Example (Kotlin) ​

kotlin
val client = WebrtcClient.Builder(this)
    .signalServerUrl("wss://your-signal-server/v1/signaling")
    .roomId("room_id_from_business")
    .token("token_from_business")
    .identityType(IdentityType.Android)
    .turnServerUrl("turn:xxx:3478")
    .lifecycleOwner(this)  // Automatically handles onPause/onResume/onDestroy once bound
    .build()

client.setStateListener(stateListener)
client.setReportListener(reportListener)
client.connect(surfaceViewContainer)

// Streaming is paused automatically on onPause, resumed on onResume, and released on onDestroy

6. Implement Callback Listeners ​

1) StateListener ​

TIP

The SDK guarantees that all callbacks are invoked on the main thread.

Callbacks fall into three categories:

  • Connection state: Socket, WebRTC, ICE, ConnectSuccess
  • Errors: Failure, CameraFail, Reconnect, KICK_OUT, CLOUD_NOT_AVAILABLE
  • Business: CurrentClarity, CloudClipData, FIRST_FRAME
kotlin
override fun onStateChanged(state: PullMonitorState) {
    when (state) {
        is PullMonitorState.OnSocketStateChanged ->
            Log.d(TAG, "Socket: ${state.socketState.getDescription()}")
        is PullMonitorState.OnWebRTCStateChanged ->
            handleStreamState(state.rtcState)
        is PullMonitorState.Failure -> {
            Toast.makeText(this, "Error: ${state.code.code} ${state.errorMessage}", Toast.LENGTH_SHORT).show()
            Log.e(TAG, "Failure: ${state.code.code} ${state.errorMessage}")
        }
        is PullMonitorState.CameraFail -> {
            Toast.makeText(this, "Camera: ${state.message}", Toast.LENGTH_SHORT).show()
            Log.e(TAG, "CameraFail: ${state.message}")
            loadingContainer?.visibility = View.GONE
        }
        is PullMonitorState.Reconnect -> {
            val msg = when (state.wasEverConnected) {
                true -> "Connection lost. Tap \"Start Streaming\" again"
                false -> "Connection failed. Check the network and retry"
                null -> "Connection error. Tap \"Start Streaming\" again"
            }
            Log.e(TAG, "$msg ==== ${state.wasEverConnected}")
            Toast.makeText(this, "$msg ==== ${state.wasEverConnected}", Toast.LENGTH_SHORT).show()
            loadingContainer?.visibility = View.VISIBLE
            tip?.text = "Reconnecting..."
            webrtcClient?.reconnect()
        }
        is PullMonitorState.OnIceStateChanged ->
            Log.d(TAG, "ICE: ${state.iceStatusMsg}")
        is PullMonitorState.OnConnectionChange ->
            Log.d(TAG, "Connection: ${state.status}")
        is PullMonitorState.ConnectSuccess ->
            Log.d(TAG, "Connected")
        is PullMonitorState.CurrentClarity ->
            level = if (state.level == 4) 1 else level + 1
        is PullMonitorState.CloudClipData ->
            Toast.makeText(this, state.data, Toast.LENGTH_SHORT).show()
        is PullMonitorState.ImeiStatus -> {
            imeiMode = state.imeiMode
            Log.e("-main-", "ImeiStatus====>" + state.imeiMode)
        }
        else -> {}
    }
}

private fun handleStreamState(rtcState: WebRTCStateType) {
    when (rtcState) {
        WebRTCStateType.FIRST_FRAME ->
            loadingContainer?.visibility = View.GONE
        WebRTCStateType.KICK_OUT ->
            Toast.makeText(this, "Kicked out of the room", Toast.LENGTH_SHORT).show()
        WebRTCStateType.CLOUD_NOT_AVAILABLE ->
            Toast.makeText(this, "The cloud phone is unavailable", Toast.LENGTH_SHORT).show()
        WebRTCStateType.ROOM_UPPER_LIMIT ->
            Toast.makeText(this, "The room connection limit has been reached", Toast.LENGTH_SHORT).show()
        else -> {}
    }
}

2) ReportListener ​

kotlin
override fun onWebRTCReport(report: WebRTCReport) {
    when (report) {
        is WebRTCReport.OnCandidateTypeReport ->
            pctText?.text = "Connection type: ${report.candidateType.getDescription()}"
        is WebRTCReport.OnNetTypeReport -> when (report.key) {
            RK_ROUND_TRIP_TIME -> rttText?.text = "Latency: ${report.value}s"
            RK_LOSS_RATE -> lrText?.text = "Packet loss: ${report.value}%"
            RK_JITTER -> jitText?.text = "Jitter: ${report.value}s"
            else -> {}
        }
    }
}

7. Cloud Phone Operations ​

FeatureCall
Start streamingwebrtcClient.connect(streamView)
Stop streamingwebrtcClient.release()
Cloud phone Back keywebrtcClient.sendCommand(CommandCode.BACK)
Cloud phone Home keywebrtcClient.sendCommand(CommandCode.HOME)
Cloud phone Recents keywebrtcClient.sendCommand(CommandCode.TASK)
Copy content to the cloud phonewebrtcClient.clipDataToCloud("content")
Volume upwebrtcClient.sendCommand(CommandCode.VOICE_ADD)
Volume downwebrtcClient.sendCommand(CommandCode.VOICE_DOWN)
MutewebrtcClient.switchImeiMode(ActionImeInputValue.DISABLE)
UnmutewebrtcClient.switchImeiMode(ActionImeInputValue.ENABLE)

OpenAPI Docs