正在显示
2 个修改的文件
包含
97 行增加
和
3 行删除
| @@ -37,14 +37,12 @@ android { | @@ -37,14 +37,12 @@ android { | ||
| 37 | 37 | ||
| 38 | protobuf { | 38 | protobuf { |
| 39 | protoc { | 39 | protoc { |
| 40 | - // You still need protoc like in the non-Android case | ||
| 41 | artifact = "com.google.protobuf:protoc:${versions.protobuf}" | 40 | artifact = "com.google.protobuf:protoc:${versions.protobuf}" |
| 42 | } | 41 | } |
| 43 | generateProtoTasks { | 42 | generateProtoTasks { |
| 44 | all().each { task -> | 43 | all().each { task -> |
| 45 | task.builtins { | 44 | task.builtins { |
| 46 | java { | 45 | java { |
| 47 | - option "lite" | ||
| 48 | } | 46 | } |
| 49 | } | 47 | } |
| 50 | } | 48 | } |
| 1 | package io.livekit.android.room | 1 | package io.livekit.android.room |
| 2 | 2 | ||
| 3 | import com.github.ajalt.timberkt.Timber | 3 | import com.github.ajalt.timberkt.Timber |
| 4 | +import com.google.protobuf.util.JsonFormat | ||
| 5 | +import livekit.Model | ||
| 6 | +import livekit.Rtc | ||
| 4 | import okhttp3.Request | 7 | import okhttp3.Request |
| 5 | import okhttp3.Response | 8 | import okhttp3.Response |
| 6 | import okhttp3.WebSocket | 9 | import okhttp3.WebSocket |
| 7 | import okhttp3.WebSocketListener | 10 | import okhttp3.WebSocketListener |
| 8 | import okio.ByteString | 11 | import okio.ByteString |
| 12 | +import org.webrtc.SessionDescription | ||
| 9 | import javax.inject.Inject | 13 | import javax.inject.Inject |
| 10 | 14 | ||
| 11 | internal class RTCClient | 15 | internal class RTCClient |
| 12 | @Inject | 16 | @Inject |
| 13 | constructor( | 17 | constructor( |
| 14 | private val websocketFactory: WebSocket.Factory, | 18 | private val websocketFactory: WebSocket.Factory, |
| 19 | + private val fromJson: JsonFormat.Parser, | ||
| 20 | + private val toJson: JsonFormat.Printer, | ||
| 15 | ) : WebSocketListener() { | 21 | ) : WebSocketListener() { |
| 16 | 22 | ||
| 17 | private var isConnected = false | 23 | private var isConnected = false |
| 18 | private var currentWs: WebSocket? = null | 24 | private var currentWs: WebSocket? = null |
| 25 | + var listener: Listener? = null | ||
| 26 | + | ||
| 19 | fun connect( | 27 | fun connect( |
| 20 | host: String, | 28 | host: String, |
| 21 | token: String, | 29 | token: String, |
| @@ -37,7 +45,21 @@ constructor( | @@ -37,7 +45,21 @@ constructor( | ||
| 37 | } | 45 | } |
| 38 | 46 | ||
| 39 | override fun onMessage(webSocket: WebSocket, text: String) { | 47 | override fun onMessage(webSocket: WebSocket, text: String) { |
| 40 | - super.onMessage(webSocket, text) | 48 | + val signalResponseBuilder = Rtc.SignalResponse.newBuilder() |
| 49 | + fromJson.merge(text, signalResponseBuilder) | ||
| 50 | + val response = signalResponseBuilder.build() | ||
| 51 | + | ||
| 52 | + if (!isConnected) { | ||
| 53 | + // Only handle joins if not connected. | ||
| 54 | + if (response.hasJoin()) { | ||
| 55 | + isConnected = true | ||
| 56 | + listener?.onJoin(response.join) | ||
| 57 | + } else { | ||
| 58 | + Timber.e { "out of order message?" } | ||
| 59 | + } | ||
| 60 | + return | ||
| 61 | + } | ||
| 62 | + handleSignalResponse(response) | ||
| 41 | } | 63 | } |
| 42 | 64 | ||
| 43 | override fun onMessage(webSocket: WebSocket, bytes: ByteString) { | 65 | override fun onMessage(webSocket: WebSocket, bytes: ByteString) { |
| @@ -56,4 +78,78 @@ constructor( | @@ -56,4 +78,78 @@ constructor( | ||
| 56 | super.onFailure(webSocket, t, response) | 78 | super.onFailure(webSocket, t, response) |
| 57 | } | 79 | } |
| 58 | 80 | ||
| 81 | + | ||
| 82 | + fun fromProtoSessionDescription(sd: Rtc.SessionDescription): SessionDescription { | ||
| 83 | + val rtcSdpType = when (sd.type) { | ||
| 84 | + SD_TYPE_ANSWER -> SessionDescription.Type.ANSWER | ||
| 85 | + SD_TYPE_OFFER -> SessionDescription.Type.OFFER | ||
| 86 | + SD_TYPE_PRANSWER -> SessionDescription.Type.PRANSWER | ||
| 87 | + else -> throw IllegalArgumentException("invalid RTC SdpType: ${sd.type}") | ||
| 88 | + } | ||
| 89 | + return SessionDescription(rtcSdpType, sd.sdp) | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + fun toProtoSessionDescription(sdp: SessionDescription): Rtc.SessionDescription { | ||
| 93 | + val sdBuilder = Rtc.SessionDescription.newBuilder() | ||
| 94 | + sdBuilder.sdp = sdp.description | ||
| 95 | + sdBuilder.type = when (sdp.type) { | ||
| 96 | + SessionDescription.Type.ANSWER -> SD_TYPE_ANSWER | ||
| 97 | + SessionDescription.Type.OFFER -> SD_TYPE_OFFER | ||
| 98 | + SessionDescription.Type.PRANSWER -> SD_TYPE_PRANSWER | ||
| 99 | + else -> throw IllegalArgumentException("invalid RTC SdpType: ${sdp.type}") | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + return sdBuilder.build() | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + fun handleSignalResponse(response: Rtc.SignalResponse) { | ||
| 106 | + if (!isConnected) { | ||
| 107 | + Timber.e { "Received response while not connected. ${toJson.print(response)}" } | ||
| 108 | + return | ||
| 109 | + } | ||
| 110 | + when (response.messageCase) { | ||
| 111 | + Rtc.SignalResponse.MessageCase.ANSWER -> { | ||
| 112 | + val sd = fromProtoSessionDescription(response.answer) | ||
| 113 | + listener?.onAnswer(sd) | ||
| 114 | + } | ||
| 115 | + Rtc.SignalResponse.MessageCase.OFFER -> { | ||
| 116 | + val sd = fromProtoSessionDescription(response.offer) | ||
| 117 | + listener?.onOffer(sd) | ||
| 118 | + } | ||
| 119 | +// Rtc.SignalResponse.MessageCase.TRICKLE -> { | ||
| 120 | +// TODO() | ||
| 121 | +// } | ||
| 122 | + Rtc.SignalResponse.MessageCase.UPDATE -> { | ||
| 123 | + listener?.onParticipantUpdate(response.update.participantsList) | ||
| 124 | + } | ||
| 125 | + Rtc.SignalResponse.MessageCase.TRACK_PUBLISHED -> { | ||
| 126 | + listener?.onLocalTrackPublished(response.trackPublished) | ||
| 127 | + } | ||
| 128 | + Rtc.SignalResponse.MessageCase.SPEAKER -> TODO() | ||
| 129 | + Rtc.SignalResponse.MessageCase.MESSAGE_NOT_SET -> TODO() | ||
| 130 | + else -> { | ||
| 131 | + Timber.v { "unhandled response type: ${response.messageCase.name}" } | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + interface Listener { | ||
| 138 | + fun onJoin(info: Rtc.JoinResponse) | ||
| 139 | + | ||
| 140 | + fun onAnswer(sessionDescription: SessionDescription) | ||
| 141 | + fun onOffer(sessionDescription: SessionDescription) | ||
| 142 | + | ||
| 143 | + //fun onTrickle(candidate: RTCIceCandidate, target: Rtc.SignalTarget) | ||
| 144 | + fun onLocalTrackPublished(trackPublished: Rtc.TrackPublishedResponse) | ||
| 145 | + fun onParticipantUpdate(updates: List<Model.ParticipantInfo>) | ||
| 146 | + fun onClose(reason: String, code: Int) | ||
| 147 | + fun onError(error: Error) | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + companion object { | ||
| 151 | + const val SD_TYPE_ANSWER = "answer" | ||
| 152 | + const val SD_TYPE_OFFER = "offer" | ||
| 153 | + const val SD_TYPE_PRANSWER = "pranswer" | ||
| 154 | + } | ||
| 59 | } | 155 | } |
-
请 注册 或 登录 后发表评论