David Liu

fool proof coroutinesdpobserver a little better

@@ -5,7 +5,7 @@ import com.github.ajalt.timberkt.Timber @@ -5,7 +5,7 @@ import com.github.ajalt.timberkt.Timber
5 import io.livekit.android.dagger.InjectionNames 5 import io.livekit.android.dagger.InjectionNames
6 import io.livekit.android.room.track.Track 6 import io.livekit.android.room.track.Track
7 import io.livekit.android.room.track.TrackException 7 import io.livekit.android.room.track.TrackException
8 -import io.livekit.android.room.util.CoroutineSdpObserver 8 +import io.livekit.android.room.util.*
9 import io.livekit.android.util.CloseableCoroutineScope 9 import io.livekit.android.util.CloseableCoroutineScope
10 import io.livekit.android.util.Either 10 import io.livekit.android.util.Either
11 import kotlinx.coroutines.CoroutineDispatcher 11 import kotlinx.coroutines.CoroutineDispatcher
@@ -101,22 +101,23 @@ constructor( @@ -101,22 +101,23 @@ constructor(
101 return 101 return
102 } 102 }
103 coroutineScope.launch { 103 coroutineScope.launch {
104 - val offerObserver = CoroutineSdpObserver()  
105 - publisher.peerConnection.createOffer(offerObserver, OFFER_CONSTRAINTS)  
106 - val sdpOffer = when (val outcome = offerObserver.awaitCreate()) {  
107 - is Either.Left -> outcome.value 104 + val sdpOffer =
  105 + when (val outcome = publisher.peerConnection.createOffer(OFFER_CONSTRAINTS)) {
  106 + is Either.Left -> outcome.value
  107 + is Either.Right -> {
  108 + Timber.d { "error creating offer: ${outcome.value}" }
  109 + return@launch
  110 + }
  111 + }
  112 +
  113 + when (val outcome = publisher.peerConnection.setLocalDescription(sdpOffer)) {
108 is Either.Right -> { 114 is Either.Right -> {
109 - Timber.d { "error creating offer: ${outcome.value}" } 115 + Timber.d { "error setting local description: ${outcome.value}" }
110 return@launch 116 return@launch
111 } 117 }
112 } 118 }
113 119
114 - val setObserver = CoroutineSdpObserver()  
115 - publisher.peerConnection.setLocalDescription(setObserver, sdpOffer)  
116 - when (val outcome = setObserver.awaitSet()) {  
117 - is Either.Left -> client.sendOffer(sdpOffer)  
118 - is Either.Right -> Timber.d { "error setting local description: ${outcome.value}" }  
119 - } 120 + client.sendOffer(sdpOffer)
120 } 121 }
121 } 122 }
122 123
@@ -163,31 +164,29 @@ constructor( @@ -163,31 +164,29 @@ constructor(
163 joinResponse = info 164 joinResponse = info
164 165
165 coroutineScope.launch { 166 coroutineScope.launch {
166 - val offerObserver = CoroutineSdpObserver()  
167 - publisher.peerConnection.createOffer(offerObserver, OFFER_CONSTRAINTS)  
168 - val sdpOffer = when (val outcome = offerObserver.awaitCreate()) {  
169 - is Either.Left -> outcome.value 167 + val sdpOffer =
  168 + when (val outcome = publisher.peerConnection.createOffer(OFFER_CONSTRAINTS)) {
  169 + is Either.Left -> outcome.value
  170 + is Either.Right -> {
  171 + Timber.d { "error creating offer: ${outcome.value}" }
  172 + return@launch
  173 + }
  174 + }
  175 +
  176 + when (val outcome = publisher.peerConnection.setLocalDescription(sdpOffer)) {
170 is Either.Right -> { 177 is Either.Right -> {
171 - Timber.d { "error creating offer: ${outcome.value}" }  
172 - return@launch 178 + Timber.d { "error setting local description: ${outcome.value}" }
173 } 179 }
174 } 180 }
175 181
176 - val setObserver = CoroutineSdpObserver()  
177 - publisher.peerConnection.setLocalDescription(setObserver, sdpOffer)  
178 - when (val outcome = setObserver.awaitSet()) {  
179 - is Either.Left -> client.sendOffer(sdpOffer)  
180 - is Either.Right -> Timber.d { "error setting local description: ${outcome.value}" }  
181 - } 182 + client.sendOffer(sdpOffer)
182 } 183 }
183 } 184 }
184 185
185 override fun onAnswer(sessionDescription: SessionDescription) { 186 override fun onAnswer(sessionDescription: SessionDescription) {
186 Timber.v { "received server answer: ${sessionDescription.type}, ${publisher.peerConnection.signalingState()}" } 187 Timber.v { "received server answer: ${sessionDescription.type}, ${publisher.peerConnection.signalingState()}" }
187 - val observer = CoroutineSdpObserver()  
188 - publisher.peerConnection.setRemoteDescription(observer, sessionDescription)  
189 coroutineScope.launch { 188 coroutineScope.launch {
190 - when (val outcome = observer.awaitSet()) { 189 + when (val outcome = publisher.peerConnection.setRemoteDescription(sessionDescription)) {
191 is Either.Left -> { 190 is Either.Left -> {
192 if (!rtcConnected) { 191 if (!rtcConnected) {
193 onRTCConnected() 192 onRTCConnected()
@@ -204,9 +203,8 @@ constructor( @@ -204,9 +203,8 @@ constructor(
204 Timber.v { "received server offer: ${sessionDescription.type}, ${subscriber.peerConnection.signalingState()}" } 203 Timber.v { "received server offer: ${sessionDescription.type}, ${subscriber.peerConnection.signalingState()}" }
205 coroutineScope.launch { 204 coroutineScope.launch {
206 run<Unit> { 205 run<Unit> {
207 - val observer = CoroutineSdpObserver()  
208 - subscriber.peerConnection.setRemoteDescription(observer, sessionDescription)  
209 - when (val outcome = observer.awaitSet()) { 206 + when (val outcome =
  207 + subscriber.peerConnection.setRemoteDescription(sessionDescription)) {
210 is Either.Right -> { 208 is Either.Right -> {
211 Timber.e { "error setting remote description for answer: ${outcome.value} " } 209 Timber.e { "error setting remote description for answer: ${outcome.value} " }
212 return@launch 210 return@launch
@@ -215,9 +213,7 @@ constructor( @@ -215,9 +213,7 @@ constructor(
215 } 213 }
216 214
217 val answer = run { 215 val answer = run {
218 - val observer = CoroutineSdpObserver()  
219 - subscriber.peerConnection.createAnswer(observer, OFFER_CONSTRAINTS)  
220 - when (val outcome = observer.awaitCreate()) { 216 + when (val outcome = subscriber.peerConnection.createAnswer(OFFER_CONSTRAINTS)) {
221 is Either.Left -> outcome.value 217 is Either.Left -> outcome.value
222 is Either.Right -> { 218 is Either.Right -> {
223 Timber.e { "error creating answer: ${outcome.value}" } 219 Timber.e { "error creating answer: ${outcome.value}" }
@@ -227,9 +223,7 @@ constructor( @@ -227,9 +223,7 @@ constructor(
227 } 223 }
228 224
229 run<Unit> { 225 run<Unit> {
230 - val observer = CoroutineSdpObserver()  
231 - subscriber.peerConnection.setLocalDescription(observer, answer)  
232 - when (val outcome = observer.awaitSet()) { 226 + when (val outcome = subscriber.peerConnection.setLocalDescription(answer)) {
233 is Either.Right -> { 227 is Either.Right -> {
234 Timber.e { "error setting local description for answer: ${outcome.value}" } 228 Timber.e { "error setting local description for answer: ${outcome.value}" }
235 return@launch 229 return@launch
1 package io.livekit.android.room.util 1 package io.livekit.android.room.util
2 2
3 import io.livekit.android.util.Either 3 import io.livekit.android.util.Either
  4 +import org.webrtc.MediaConstraints
  5 +import org.webrtc.PeerConnection
4 import org.webrtc.SdpObserver 6 import org.webrtc.SdpObserver
5 import org.webrtc.SessionDescription 7 import org.webrtc.SessionDescription
6 import kotlin.coroutines.Continuation 8 import kotlin.coroutines.Continuation
@@ -71,4 +73,28 @@ class CoroutineSdpObserver : SdpObserver { @@ -71,4 +73,28 @@ class CoroutineSdpObserver : SdpObserver {
71 pendingSets.add(cont) 73 pendingSets.add(cont)
72 } 74 }
73 } 75 }
  76 +}
  77 +
  78 +suspend fun PeerConnection.createOffer(constraints: MediaConstraints): Either<SessionDescription, String?> {
  79 + val observer = CoroutineSdpObserver()
  80 + this.createOffer(observer, constraints)
  81 + return observer.awaitCreate()
  82 +}
  83 +
  84 +suspend fun PeerConnection.createAnswer(constraints: MediaConstraints): Either<SessionDescription, String?> {
  85 + val observer = CoroutineSdpObserver()
  86 + this.createAnswer(observer, constraints)
  87 + return observer.awaitCreate()
  88 +}
  89 +
  90 +suspend fun PeerConnection.setRemoteDescription(description: SessionDescription): Either<Unit, String?> {
  91 + val observer = CoroutineSdpObserver()
  92 + this.setRemoteDescription(observer, description)
  93 + return observer.awaitSet()
  94 +}
  95 +
  96 +suspend fun PeerConnection.setLocalDescription(description: SessionDescription): Either<Unit, String?> {
  97 + val observer = CoroutineSdpObserver()
  98 + this.setLocalDescription(observer, description)
  99 + return observer.awaitSet()
74 } 100 }
@@ -14,7 +14,6 @@ import kotlinx.parcelize.Parcelize @@ -14,7 +14,6 @@ import kotlinx.parcelize.Parcelize
14 class CallActivity : AppCompatActivity() { 14 class CallActivity : AppCompatActivity() {
15 15
16 val viewModel: CallViewModel by viewModelByFactory { 16 val viewModel: CallViewModel by viewModelByFactory {
17 -  
18 val args = intent.getParcelableExtra<BundleArgs>(KEY_ARGS) 17 val args = intent.getParcelableExtra<BundleArgs>(KEY_ARGS)
19 ?: throw NullPointerException("args is null!") 18 ?: throw NullPointerException("args is null!")
20 CallViewModel(args.url, args.token, application) 19 CallViewModel(args.url, args.token, application)
@@ -10,8 +10,6 @@ import io.livekit.android.room.track.RemoteVideoTrackPublication @@ -10,8 +10,6 @@ import io.livekit.android.room.track.RemoteVideoTrackPublication
10 import io.livekit.android.room.track.VideoTrack 10 import io.livekit.android.room.track.VideoTrack
11 import io.livekit.android.room.track.VideoTrackPublication 11 import io.livekit.android.room.track.VideoTrackPublication
12 import io.livekit.android.sample.databinding.ParticipantItemBinding 12 import io.livekit.android.sample.databinding.ParticipantItemBinding
13 -import org.webrtc.VideoFrame  
14 -import org.webrtc.VideoSink  
15 13
16 class ParticipantItem( 14 class ParticipantItem(
17 val room: Room, 15 val room: Room,
@@ -63,12 +61,6 @@ class ParticipantItem( @@ -63,12 +61,6 @@ class ParticipantItem(
63 61
64 videoBound = true 62 videoBound = true
65 Timber.v { "adding renderer to $videoTrack" } 63 Timber.v { "adding renderer to $videoTrack" }
66 - videoTrack.addRenderer(object : VideoSink {  
67 - override fun onFrame(frame: VideoFrame?) {  
68 - Timber.v { "$frame" }  
69 - }  
70 -  
71 - })  
72 videoTrack.addRenderer(viewBinding.renderer) 64 videoTrack.addRenderer(viewBinding.renderer)
73 } 65 }
74 66