Skip to content

Android SDK 集成与使用步骤 ​

一、环境要求 ​

项目要求
Android 最低版本minSdk 27(Android 8.1,推荐)
支持的 CPU 架构armeabi-v7a、arm64-v8a、x86、x86_64

如需按架构过滤,在应用模块 build.gradle 的 defaultConfig 中配置 abiFilters:

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

二、引入 aar 文件 ​

将 webrtc-pull-stream-release.aar 复制到应用模块的 app/libs 目录,并在 build.gradle 中添加依赖:

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

三、权限声明 ​

在 AndroidManifest.xml 中声明 SDK 所需权限:

xml
<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 麦克风权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

TIP

CAMERA 与 RECORD_AUDIO 属于危险权限,Android 6.0 及以上需在运行时动态申请。

四、布局文件添加 PullStreamView ​

在布局 xml 中写入 PullStreamView 控件:

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"
/>

五、初始化 WebrtcClient ​

初始化所需参数 ​

  1. signalServerUrl:信令服务地址
  2. roomId:房间 ID
  3. Token:业务 token
  4. turnServerUrl:turn 服务地址

初始化代码示例(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)  // 绑定后自动处理 onPause/onResume/onDestroy
    .build()

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

// onPause 时自动暂停拉流,onResume 时自动恢复,onDestroy 时自动 release

六、回调监听实现 ​

1)StateListener 状态回调 ​

TIP

SDK 已保证回调在主线程执行。

回调按类型分为:

  • 连接状态:Socket、WebRTC、ICE、ConnectSuccess
  • 错误:Failure、CameraFail、Reconnect、KICK_OUT、CLOUD_NOT_AVAILABLE
  • 业务: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, "错误: ${state.code.code} ${state.errorMessage}", Toast.LENGTH_SHORT).show()
            Log.e(TAG, "Failure: ${state.code.code} ${state.errorMessage}")
        }
        is PullMonitorState.CameraFail -> {
            Toast.makeText(this, "摄像头: ${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 -> "连接已断开,请重新点击「开始拉流」"
                false -> "连接失败,请检查网络后重试"
                null -> "连接异常,请重新点击「开始拉流」"
            }
            Log.e(TAG, "$msg ==== ${state.wasEverConnected}")
            Toast.makeText(this, "$msg ==== ${state.wasEverConnected}", Toast.LENGTH_SHORT).show()
            loadingContainer?.visibility = View.VISIBLE
            tip?.text = "重连中..."
            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, "连接成功")
        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, "已被踢出房间", Toast.LENGTH_SHORT).show()
        WebRTCStateType.CLOUD_NOT_AVAILABLE ->
            Toast.makeText(this, "当前云机不可用", Toast.LENGTH_SHORT).show()
        WebRTCStateType.ROOM_UPPER_LIMIT ->
            Toast.makeText(this, "房间连接数已满", Toast.LENGTH_SHORT).show()
        else -> {}
    }
}

2)ReportListener 统计上报回调 ​

kotlin
override fun onWebRTCReport(report: WebRTCReport) {
    when (report) {
        is WebRTCReport.OnCandidateTypeReport ->
            pctText?.text = "当前连接方式: ${report.candidateType.getDescription()}"
        is WebRTCReport.OnNetTypeReport -> when (report.key) {
            RK_ROUND_TRIP_TIME -> rttText?.text = "延迟: ${report.value}秒"
            RK_LOSS_RATE -> lrText?.text = "丢包率: ${report.value}%"
            RK_JITTER -> jitText?.text = "抖动: ${report.value}秒"
            else -> {}
        }
    }
}

七、云机操作调用方法 ​

功能调用代码
开始拉流webrtcClient.connect(streamView)
停止拉流webrtcClient.release()
云机返回键webrtcClient.sendCommand(CommandCode.BACK)
云机 HOME 键webrtcClient.sendCommand(CommandCode.HOME)
云机任务键webrtcClient.sendCommand(CommandCode.TASK)
复制内容到云机webrtcClient.clipDataToCloud("内容")
音量增加webrtcClient.sendCommand(CommandCode.VOICE_ADD)
音量减小webrtcClient.sendCommand(CommandCode.VOICE_DOWN)
静音操作webrtcClient.switchImeiMode(ActionImeInputValue.DISABLE)
解除静音webrtcClient.switchImeiMode(ActionImeInputValue.ENABLE)

OpenAPI Docs