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
初始化所需参数
signalServerUrl:信令服务地址roomId:房间 IDToken:业务 tokenturnServerUrl: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) |
