正在显示
9 个修改的文件
包含
258 行增加
和
39 行删除
| @@ -180,6 +180,32 @@ constructor( | @@ -180,6 +180,32 @@ constructor( | ||
| 180 | sendRequest(request) | 180 | sendRequest(request) |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | + fun sendUpdateTrackSettings(sid: String, disabled: Boolean, videoQuality: LivekitRtc.VideoQuality) { | ||
| 184 | + val trackSettings = LivekitRtc.UpdateTrackSettings.newBuilder() | ||
| 185 | + .setTrackSids(0, sid) | ||
| 186 | + .setDisabled(disabled) | ||
| 187 | + .setQuality(videoQuality) | ||
| 188 | + | ||
| 189 | + val request = LivekitRtc.SignalRequest.newBuilder() | ||
| 190 | + .setTrackSetting(trackSettings) | ||
| 191 | + .build() | ||
| 192 | + | ||
| 193 | + sendRequest(request) | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + fun sendUpdateSubscription(sid: String, subscribe: Boolean, videoQuality: LivekitRtc.VideoQuality) { | ||
| 197 | + val subscription = LivekitRtc.UpdateSubscription.newBuilder() | ||
| 198 | + .setTrackSids(0, sid) | ||
| 199 | + .setSubscribe(subscribe) | ||
| 200 | + .setQuality(videoQuality) | ||
| 201 | + | ||
| 202 | + val request = LivekitRtc.SignalRequest.newBuilder() | ||
| 203 | + .setSubscription(subscription) | ||
| 204 | + .build() | ||
| 205 | + | ||
| 206 | + sendRequest(request) | ||
| 207 | + } | ||
| 208 | + | ||
| 183 | fun sendRequest(request: LivekitRtc.SignalRequest) { | 209 | fun sendRequest(request: LivekitRtc.SignalRequest) { |
| 184 | Timber.v { "sending request: $request" } | 210 | Timber.v { "sending request: $request" } |
| 185 | if (!isConnected || currentWs == null) { | 211 | if (!isConnected || currentWs == null) { |
| @@ -9,9 +9,7 @@ import io.livekit.android.room.participant.LocalParticipant | @@ -9,9 +9,7 @@ import io.livekit.android.room.participant.LocalParticipant | ||
| 9 | import io.livekit.android.room.participant.Participant | 9 | import io.livekit.android.room.participant.Participant |
| 10 | import io.livekit.android.room.participant.ParticipantListener | 10 | import io.livekit.android.room.participant.ParticipantListener |
| 11 | import io.livekit.android.room.participant.RemoteParticipant | 11 | import io.livekit.android.room.participant.RemoteParticipant |
| 12 | -import io.livekit.android.room.track.DataTrack | ||
| 13 | -import io.livekit.android.room.track.Track | ||
| 14 | -import io.livekit.android.room.track.TrackPublication | 12 | +import io.livekit.android.room.track.* |
| 15 | import io.livekit.android.room.util.unpackedTrackLabel | 13 | import io.livekit.android.room.util.unpackedTrackLabel |
| 16 | import livekit.LivekitModels | 14 | import livekit.LivekitModels |
| 17 | import livekit.LivekitRtc | 15 | import livekit.LivekitRtc |
| @@ -92,9 +90,9 @@ constructor( | @@ -92,9 +90,9 @@ constructor( | ||
| 92 | } | 90 | } |
| 93 | 91 | ||
| 94 | participant = if (info != null) { | 92 | participant = if (info != null) { |
| 95 | - RemoteParticipant(info) | 93 | + RemoteParticipant(engine.client, info) |
| 96 | } else { | 94 | } else { |
| 97 | - RemoteParticipant(sid, null) | 95 | + RemoteParticipant(engine.client, sid, null) |
| 98 | } | 96 | } |
| 99 | participant.internalListener = this | 97 | participant.internalListener = this |
| 100 | mutableRemoteParticipants[sid] = participant | 98 | mutableRemoteParticipants[sid] = participant |
| @@ -258,24 +256,34 @@ constructor( | @@ -258,24 +256,34 @@ constructor( | ||
| 258 | listener?.onMetadataChanged(participant, prevMetadata, this) | 256 | listener?.onMetadataChanged(participant, prevMetadata, this) |
| 259 | } | 257 | } |
| 260 | 258 | ||
| 259 | + /** @suppress */ | ||
| 260 | + override fun onTrackMuted(publication: TrackPublication, participant: Participant) { | ||
| 261 | + listener?.onTrackMuted(publication, participant, this) | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + /** @suppress */ | ||
| 265 | + override fun onTrackUnmuted(publication: TrackPublication, participant: Participant) { | ||
| 266 | + listener?.onTrackUnmuted(publication, participant, this) | ||
| 267 | + } | ||
| 268 | + | ||
| 261 | /** | 269 | /** |
| 262 | * @suppress | 270 | * @suppress |
| 263 | */ | 271 | */ |
| 264 | - override fun onTrackPublished(publication: TrackPublication, participant: RemoteParticipant) { | 272 | + override fun onTrackPublished(publication: RemoteTrackPublication, participant: RemoteParticipant) { |
| 265 | listener?.onTrackPublished(publication, participant, this) | 273 | listener?.onTrackPublished(publication, participant, this) |
| 266 | } | 274 | } |
| 267 | 275 | ||
| 268 | /** | 276 | /** |
| 269 | * @suppress | 277 | * @suppress |
| 270 | */ | 278 | */ |
| 271 | - override fun onTrackUnpublished(publication: TrackPublication, participant: RemoteParticipant) { | 279 | + override fun onTrackUnpublished(publication: RemoteTrackPublication, participant: RemoteParticipant) { |
| 272 | listener?.onTrackUnpublished(publication, participant, this) | 280 | listener?.onTrackUnpublished(publication, participant, this) |
| 273 | } | 281 | } |
| 274 | 282 | ||
| 275 | /** | 283 | /** |
| 276 | * @suppress | 284 | * @suppress |
| 277 | */ | 285 | */ |
| 278 | - override fun onTrackSubscribed(track: Track, publication: TrackPublication, participant: RemoteParticipant) { | 286 | + override fun onTrackSubscribed(track: Track, publication: RemoteTrackPublication, participant: RemoteParticipant) { |
| 279 | listener?.onTrackSubscribed(track, publication, participant, this) | 287 | listener?.onTrackSubscribed(track, publication, participant, this) |
| 280 | } | 288 | } |
| 281 | 289 | ||
| @@ -295,7 +303,7 @@ constructor( | @@ -295,7 +303,7 @@ constructor( | ||
| 295 | */ | 303 | */ |
| 296 | override fun onTrackUnsubscribed( | 304 | override fun onTrackUnsubscribed( |
| 297 | track: Track, | 305 | track: Track, |
| 298 | - publication: TrackPublication, | 306 | + publication: RemoteTrackPublication, |
| 299 | participant: RemoteParticipant | 307 | participant: RemoteParticipant |
| 300 | ) { | 308 | ) { |
| 301 | listener?.onTrackUnsubscribed(track, publication, participant, this) | 309 | listener?.onTrackUnsubscribed(track, publication, participant, this) |
| @@ -366,6 +374,22 @@ interface RoomListener { | @@ -366,6 +374,22 @@ interface RoomListener { | ||
| 366 | fun onMetadataChanged(participant: Participant, prevMetadata: String?, room: Room) {} | 374 | fun onMetadataChanged(participant: Participant, prevMetadata: String?, room: Room) {} |
| 367 | 375 | ||
| 368 | /** | 376 | /** |
| 377 | + * The participant was muted. | ||
| 378 | + * | ||
| 379 | + * For the local participant, the callback will be called if setMute was called on the | ||
| 380 | + * [LocalTrackPublication], or if the server has requested the participant to be muted | ||
| 381 | + */ | ||
| 382 | + fun onTrackMuted(publication: TrackPublication, participant: Participant, room: Room) {} | ||
| 383 | + | ||
| 384 | + /** | ||
| 385 | + * The participant was unmuted. | ||
| 386 | + * | ||
| 387 | + * For the local participant, the callback will be called if setMute was called on the | ||
| 388 | + * [LocalTrackPublication], or if the server has requested the participant to be muted | ||
| 389 | + */ | ||
| 390 | + fun onTrackUnmuted(publication: TrackPublication, participant: Participant, room: Room) {} | ||
| 391 | + | ||
| 392 | + /** | ||
| 369 | * When a new track is published to room after the local participant has joined. It will | 393 | * When a new track is published to room after the local participant has joined. It will |
| 370 | * not fire for tracks that are already published | 394 | * not fire for tracks that are already published |
| 371 | */ | 395 | */ |
| @@ -15,7 +15,7 @@ class LocalParticipant | @@ -15,7 +15,7 @@ class LocalParticipant | ||
| 15 | internal constructor( | 15 | internal constructor( |
| 16 | @Assisted | 16 | @Assisted |
| 17 | info: LivekitModels.ParticipantInfo, | 17 | info: LivekitModels.ParticipantInfo, |
| 18 | - private val engine: RTCEngine, | 18 | + internal val engine: RTCEngine, |
| 19 | private val peerConnectionFactory: PeerConnectionFactory, | 19 | private val peerConnectionFactory: PeerConnectionFactory, |
| 20 | private val context: Context, | 20 | private val context: Context, |
| 21 | private val eglBase: EglBase, | 21 | private val eglBase: EglBase, |
| @@ -72,7 +72,7 @@ internal constructor( | @@ -72,7 +72,7 @@ internal constructor( | ||
| 72 | return | 72 | return |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | - val publication = TrackPublication(trackInfo, track) | 75 | + val publication = LocalTrackPublication(trackInfo, track, this) |
| 76 | addTrackPublication(publication) | 76 | addTrackPublication(publication) |
| 77 | publishListener?.onPublishSuccess(publication) | 77 | publishListener?.onPublishSuccess(publication) |
| 78 | } | 78 | } |
| @@ -102,7 +102,7 @@ internal constructor( | @@ -102,7 +102,7 @@ internal constructor( | ||
| 102 | return | 102 | return |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | - val publication = TrackPublication(trackInfo, track) | 105 | + val publication = LocalTrackPublication(trackInfo, track, this) |
| 106 | addTrackPublication(publication) | 106 | addTrackPublication(publication) |
| 107 | publishListener?.onPublishSuccess(publication) | 107 | publishListener?.onPublishSuccess(publication) |
| 108 | } | 108 | } |
| @@ -120,7 +120,7 @@ internal constructor( | @@ -120,7 +120,7 @@ internal constructor( | ||
| 120 | val cid = track.name | 120 | val cid = track.name |
| 121 | val trackInfo = | 121 | val trackInfo = |
| 122 | engine.addTrack(cid = cid, name = track.name, track.kind) | 122 | engine.addTrack(cid = cid, name = track.name, track.kind) |
| 123 | - val publication = TrackPublication(trackInfo, track) | 123 | + val publication = LocalTrackPublication(trackInfo, track, this) |
| 124 | 124 | ||
| 125 | val config = DataChannel.Init().apply { | 125 | val config = DataChannel.Init().apply { |
| 126 | ordered = track.options.ordered | 126 | ordered = track.options.ordered |
| @@ -159,15 +159,27 @@ internal constructor( | @@ -159,15 +159,27 @@ internal constructor( | ||
| 159 | } | 159 | } |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | + override fun updateFromInfo(info: LivekitModels.ParticipantInfo) { | ||
| 163 | + super.updateFromInfo(info) | ||
| 164 | + | ||
| 165 | + // detect tracks that have been muted on the server side, apply those changes | ||
| 166 | + for (ti in info.tracksList) { | ||
| 167 | + val publication = this.tracks[ti.sid] as? LocalTrackPublication ?: continue | ||
| 168 | + if (ti.muted != publication.muted) { | ||
| 169 | + publication.setMuted(ti.muted) | ||
| 170 | + } | ||
| 171 | + } | ||
| 172 | + } | ||
| 173 | + | ||
| 162 | private fun <T> unpublishMediaTrack( | 174 | private fun <T> unpublishMediaTrack( |
| 163 | track: T, | 175 | track: T, |
| 164 | sid: String | 176 | sid: String |
| 165 | ) where T : MediaTrack { | 177 | ) where T : MediaTrack { |
| 166 | - val senders = engine?.publisher?.peerConnection?.senders ?: return | 178 | + val senders = engine.publisher?.peerConnection?.senders ?: return |
| 167 | for (sender in senders) { | 179 | for (sender in senders) { |
| 168 | val t = sender.track() ?: continue | 180 | val t = sender.track() ?: continue |
| 169 | if (t == track.rtcTrack) { | 181 | if (t == track.rtcTrack) { |
| 170 | - engine?.publisher?.peerConnection?.removeTrack(sender) | 182 | + engine.publisher?.peerConnection?.removeTrack(sender) |
| 171 | } | 183 | } |
| 172 | } | 184 | } |
| 173 | } | 185 | } |
| @@ -60,7 +60,7 @@ open class Participant(var sid: String, identity: String? = null) { | @@ -60,7 +60,7 @@ open class Participant(var sid: String, identity: String? = null) { | ||
| 60 | /** | 60 | /** |
| 61 | * @suppress | 61 | * @suppress |
| 62 | */ | 62 | */ |
| 63 | - open fun updateFromInfo(info: LivekitModels.ParticipantInfo) { | 63 | + internal open fun updateFromInfo(info: LivekitModels.ParticipantInfo) { |
| 64 | sid = info.sid | 64 | sid = info.sid |
| 65 | identity = info.identity | 65 | identity = info.identity |
| 66 | participantInfo = info | 66 | participantInfo = info |
| @@ -92,6 +92,7 @@ open class Participant(var sid: String, identity: String? = null) { | @@ -92,6 +92,7 @@ open class Participant(var sid: String, identity: String? = null) { | ||
| 92 | 92 | ||
| 93 | 93 | ||
| 94 | interface ParticipantListener { | 94 | interface ParticipantListener { |
| 95 | + // all participants | ||
| 95 | /** | 96 | /** |
| 96 | * When a participant's metadata is updated, fired for all participants | 97 | * When a participant's metadata is updated, fired for all participants |
| 97 | */ | 98 | */ |
| @@ -102,13 +103,44 @@ interface ParticipantListener { | @@ -102,13 +103,44 @@ interface ParticipantListener { | ||
| 102 | */ | 103 | */ |
| 103 | fun onSpeakingChanged(participant: Participant) {} | 104 | fun onSpeakingChanged(participant: Participant) {} |
| 104 | 105 | ||
| 105 | - fun onTrackPublished(publication: TrackPublication, participant: RemoteParticipant) {} | ||
| 106 | - fun onTrackUnpublished(publication: TrackPublication, participant: RemoteParticipant) {} | 106 | + /** |
| 107 | + * The participant was muted. | ||
| 108 | + * | ||
| 109 | + * For the local participant, the callback will be called if setMute was called on the | ||
| 110 | + * [LocalTrackPublication], or if the server has requested the participant to be muted | ||
| 111 | + */ | ||
| 112 | + fun onTrackMuted(publication: TrackPublication, participant: Participant) {} | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * The participant was unmuted. | ||
| 116 | + * | ||
| 117 | + * For the local participant, the callback will be called if setMute was called on the | ||
| 118 | + * [LocalTrackPublication], or if the server has requested the participant to be muted | ||
| 119 | + */ | ||
| 120 | + fun onTrackUnmuted(publication: TrackPublication, participant: Participant) {} | ||
| 121 | + | ||
| 107 | 122 | ||
| 108 | - fun onEnable(publication: TrackPublication, participant: RemoteParticipant) {} | ||
| 109 | - fun onDisable(publication: TrackPublication, participant: RemoteParticipant) {} | 123 | + // remote participants |
| 124 | + /** | ||
| 125 | + * When a new track is published to room after the local participant has joined. | ||
| 126 | + * | ||
| 127 | + * It will not fire for tracks that are already published | ||
| 128 | + */ | ||
| 129 | + fun onTrackPublished(publication: RemoteTrackPublication, participant: RemoteParticipant) {} | ||
| 130 | + | ||
| 131 | + /** | ||
| 132 | + * A [RemoteParticipant] has unpublished a track | ||
| 133 | + */ | ||
| 134 | + fun onTrackUnpublished(publication: RemoteTrackPublication, participant: RemoteParticipant) {} | ||
| 110 | 135 | ||
| 111 | - fun onTrackSubscribed(track: Track, publication: TrackPublication, participant: RemoteParticipant) {} | 136 | + /** |
| 137 | + * Subscribed to a new track | ||
| 138 | + */ | ||
| 139 | + fun onTrackSubscribed(track: Track, publication: RemoteTrackPublication, participant: RemoteParticipant) {} | ||
| 140 | + | ||
| 141 | + /** | ||
| 142 | + * Error had occurred while subscribing to a track | ||
| 143 | + */ | ||
| 112 | fun onTrackSubscriptionFailed( | 144 | fun onTrackSubscriptionFailed( |
| 113 | sid: String, | 145 | sid: String, |
| 114 | exception: Exception, | 146 | exception: Exception, |
| @@ -116,20 +148,24 @@ interface ParticipantListener { | @@ -116,20 +148,24 @@ interface ParticipantListener { | ||
| 116 | ) { | 148 | ) { |
| 117 | } | 149 | } |
| 118 | 150 | ||
| 151 | + /** | ||
| 152 | + * A subscribed track is no longer available. | ||
| 153 | + * Clients should listen to this event and handle cleanup | ||
| 154 | + */ | ||
| 119 | fun onTrackUnsubscribed( | 155 | fun onTrackUnsubscribed( |
| 120 | track: Track, | 156 | track: Track, |
| 121 | - publication: TrackPublication, | 157 | + publication: RemoteTrackPublication, |
| 122 | participant: RemoteParticipant | 158 | participant: RemoteParticipant |
| 123 | ) { | 159 | ) { |
| 124 | } | 160 | } |
| 125 | 161 | ||
| 162 | + /** | ||
| 163 | + * Data was received on a data track | ||
| 164 | + */ | ||
| 126 | fun onDataReceived( | 165 | fun onDataReceived( |
| 127 | data: ByteBuffer, | 166 | data: ByteBuffer, |
| 128 | dataTrack: DataTrack, | 167 | dataTrack: DataTrack, |
| 129 | participant: RemoteParticipant | 168 | participant: RemoteParticipant |
| 130 | ) { | 169 | ) { |
| 131 | } | 170 | } |
| 132 | - | ||
| 133 | - fun switchedOffVideo(track: VideoTrack, publication: TrackPublication, participant: RemoteParticipant) {} | ||
| 134 | - fun switchedOnVideo(track: VideoTrack, publication: TrackPublication, participant: RemoteParticipant) {} | ||
| 135 | } | 171 | } |
| 1 | package io.livekit.android.room.participant | 1 | package io.livekit.android.room.participant |
| 2 | 2 | ||
| 3 | import com.github.ajalt.timberkt.Timber | 3 | import com.github.ajalt.timberkt.Timber |
| 4 | +import io.livekit.android.room.RTCClient | ||
| 4 | import io.livekit.android.room.track.* | 5 | import io.livekit.android.room.track.* |
| 5 | import io.livekit.android.util.CloseableCoroutineScope | 6 | import io.livekit.android.util.CloseableCoroutineScope |
| 6 | import kotlinx.coroutines.SupervisorJob | 7 | import kotlinx.coroutines.SupervisorJob |
| @@ -11,21 +12,21 @@ import org.webrtc.AudioTrack | @@ -11,21 +12,21 @@ import org.webrtc.AudioTrack | ||
| 11 | import org.webrtc.DataChannel | 12 | import org.webrtc.DataChannel |
| 12 | import org.webrtc.MediaStreamTrack | 13 | import org.webrtc.MediaStreamTrack |
| 13 | import org.webrtc.VideoTrack | 14 | import org.webrtc.VideoTrack |
| 14 | -import java.nio.ByteBuffer | ||
| 15 | 15 | ||
| 16 | class RemoteParticipant( | 16 | class RemoteParticipant( |
| 17 | - sid: String, name: String? = null | 17 | + val rtcClient: RTCClient, |
| 18 | + sid: String, name: String? = null, | ||
| 18 | ) : Participant(sid, name) { | 19 | ) : Participant(sid, name) { |
| 19 | /** | 20 | /** |
| 20 | * @suppress | 21 | * @suppress |
| 21 | */ | 22 | */ |
| 22 | - constructor(info: LivekitModels.ParticipantInfo) : this(info.sid, info.identity) { | 23 | + constructor(rtcClient: RTCClient, info: LivekitModels.ParticipantInfo) : this(rtcClient, info.sid, info.identity) { |
| 23 | updateFromInfo(info) | 24 | updateFromInfo(info) |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | private val coroutineScope = CloseableCoroutineScope(SupervisorJob()) | 27 | private val coroutineScope = CloseableCoroutineScope(SupervisorJob()) |
| 27 | 28 | ||
| 28 | - fun getTrackPublication(sid: String): TrackPublication? = tracks[sid] | 29 | + fun getTrackPublication(sid: String): RemoteTrackPublication? = tracks[sid] as? RemoteTrackPublication |
| 29 | 30 | ||
| 30 | /** | 31 | /** |
| 31 | * @suppress | 32 | * @suppress |
| @@ -34,15 +35,15 @@ class RemoteParticipant( | @@ -34,15 +35,15 @@ class RemoteParticipant( | ||
| 34 | val hadInfo = hasInfo | 35 | val hadInfo = hasInfo |
| 35 | super.updateFromInfo(info) | 36 | super.updateFromInfo(info) |
| 36 | 37 | ||
| 37 | - val validTrackPublication = mutableMapOf<String, TrackPublication>() | ||
| 38 | - val newTrackPublications = mutableMapOf<String, TrackPublication>() | 38 | + val validTrackPublication = mutableMapOf<String, RemoteTrackPublication>() |
| 39 | + val newTrackPublications = mutableMapOf<String, RemoteTrackPublication>() | ||
| 39 | 40 | ||
| 40 | for (trackInfo in info.tracksList) { | 41 | for (trackInfo in info.tracksList) { |
| 41 | val trackSid = trackInfo.sid | 42 | val trackSid = trackInfo.sid |
| 42 | var publication = getTrackPublication(trackSid) | 43 | var publication = getTrackPublication(trackSid) |
| 43 | 44 | ||
| 44 | if (publication == null) { | 45 | if (publication == null) { |
| 45 | - publication = TrackPublication(trackInfo) | 46 | + publication = RemoteTrackPublication(trackInfo, participant = this) |
| 46 | 47 | ||
| 47 | newTrackPublications[trackSid] = publication | 48 | newTrackPublications[trackSid] = publication |
| 48 | addTrackPublication(publication) | 49 | addTrackPublication(publication) |
| @@ -119,7 +120,7 @@ class RemoteParticipant( | @@ -119,7 +120,7 @@ class RemoteParticipant( | ||
| 119 | .setName(name) | 120 | .setName(name) |
| 120 | .setType(LivekitModels.TrackType.DATA) | 121 | .setType(LivekitModels.TrackType.DATA) |
| 121 | .build() | 122 | .build() |
| 122 | - publication = TrackPublication(info = trackInfo) | 123 | + publication = RemoteTrackPublication(info = trackInfo, participant = this) |
| 123 | addTrackPublication(publication) | 124 | addTrackPublication(publication) |
| 124 | if (hasInfo) { | 125 | if (hasInfo) { |
| 125 | internalListener?.onTrackPublished(publication, this) | 126 | internalListener?.onTrackPublished(publication, this) |
| @@ -151,7 +152,7 @@ class RemoteParticipant( | @@ -151,7 +152,7 @@ class RemoteParticipant( | ||
| 151 | } | 152 | } |
| 152 | 153 | ||
| 153 | fun unpublishTrack(trackSid: String, sendUnpublish: Boolean = false) { | 154 | fun unpublishTrack(trackSid: String, sendUnpublish: Boolean = false) { |
| 154 | - val publication = tracks.remove(trackSid) ?: return | 155 | + val publication = tracks.remove(trackSid) as? RemoteTrackPublication ?: return |
| 155 | when (publication.kind) { | 156 | when (publication.kind) { |
| 156 | LivekitModels.TrackType.AUDIO -> audioTracks.remove(trackSid) | 157 | LivekitModels.TrackType.AUDIO -> audioTracks.remove(trackSid) |
| 157 | LivekitModels.TrackType.VIDEO -> videoTracks.remove(trackSid) | 158 | LivekitModels.TrackType.VIDEO -> videoTracks.remove(trackSid) |
| 1 | +package io.livekit.android.room.track | ||
| 2 | + | ||
| 3 | +import io.livekit.android.room.participant.LocalParticipant | ||
| 4 | +import livekit.LivekitModels | ||
| 5 | + | ||
| 6 | +class LocalTrackPublication(info: LivekitModels.TrackInfo, | ||
| 7 | + track: Track? = null, | ||
| 8 | + participant: LocalParticipant? = null) : TrackPublication(info, track, participant) { | ||
| 9 | + | ||
| 10 | + /** | ||
| 11 | + * Mute or unmute the current track. Muting the track would stop audio or video from being | ||
| 12 | + * transmitted to the server, and notify other participants in the room. | ||
| 13 | + */ | ||
| 14 | + fun setMuted(muted: Boolean) { | ||
| 15 | + if (muted == this.muted) { | ||
| 16 | + return | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + val mediaTrack = track as? MediaTrack ?: return | ||
| 20 | + | ||
| 21 | + mediaTrack.rtcTrack.setEnabled(!muted) | ||
| 22 | + this.muted = muted | ||
| 23 | + | ||
| 24 | + // send updates to server | ||
| 25 | + val participant = this.participant.get() as? LocalParticipant ?: return | ||
| 26 | + | ||
| 27 | + participant.engine.updateMuteStatus(sid, muted) | ||
| 28 | + | ||
| 29 | + if (muted) { | ||
| 30 | + participant.listener?.onTrackMuted(this, participant) | ||
| 31 | + participant.internalListener?.onTrackMuted(this, participant) | ||
| 32 | + } else { | ||
| 33 | + participant.listener?.onTrackUnmuted(this, participant) | ||
| 34 | + participant.internalListener?.onTrackUnmuted(this, participant) | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | +} |
livekit-android-sdk/src/main/java/io/livekit/android/room/track/RemoteTrackPublication.kt
0 → 100644
| 1 | +package io.livekit.android.room.track | ||
| 2 | + | ||
| 3 | +import io.livekit.android.room.participant.RemoteParticipant | ||
| 4 | +import livekit.LivekitModels | ||
| 5 | +import livekit.LivekitRtc | ||
| 6 | + | ||
| 7 | +class RemoteTrackPublication(info: LivekitModels.TrackInfo, | ||
| 8 | + track: Track? = null, participant: | ||
| 9 | + RemoteParticipant? = null): TrackPublication(info, track, participant) { | ||
| 10 | + | ||
| 11 | + private var unsubscribed: Boolean = false | ||
| 12 | + private var disabled: Boolean = false | ||
| 13 | + private var videoQuality: LivekitRtc.VideoQuality = LivekitRtc.VideoQuality.HIGH | ||
| 14 | + | ||
| 15 | + override val subscribed: Boolean | ||
| 16 | + get() { | ||
| 17 | + if (unsubscribed) { | ||
| 18 | + return false | ||
| 19 | + } | ||
| 20 | + return super.subscribed | ||
| 21 | + } | ||
| 22 | + override var muted: Boolean = false | ||
| 23 | + set(v) { | ||
| 24 | + if (field == v) { | ||
| 25 | + return | ||
| 26 | + } | ||
| 27 | + field = v | ||
| 28 | + val participant = this.participant.get() as? RemoteParticipant ?: return | ||
| 29 | + if (v) { | ||
| 30 | + participant.listener?.onTrackMuted(this, participant) | ||
| 31 | + participant.internalListener?.onTrackMuted(this, participant) | ||
| 32 | + } else { | ||
| 33 | + participant.listener?.onTrackUnmuted(this, participant) | ||
| 34 | + participant.internalListener?.onTrackUnmuted(this, participant) | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * subscribe or unsubscribe from this track | ||
| 40 | + */ | ||
| 41 | + fun setSubscribed(subscribed: Boolean) { | ||
| 42 | + unsubscribed = !subscribed | ||
| 43 | + val participant = this.participant.get() as? RemoteParticipant ?: return | ||
| 44 | + | ||
| 45 | + participant.rtcClient.sendUpdateSubscription(sid, !unsubscribed, videoQuality) | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * disable server from sending down data for this track | ||
| 50 | + * | ||
| 51 | + * this is useful when the participant is off screen, you may disable streaming down their | ||
| 52 | + * video to reduce bandwidth requirements | ||
| 53 | + */ | ||
| 54 | + fun setEnabled(enabled: Boolean) { | ||
| 55 | + disabled = !enabled | ||
| 56 | + sendUpdateTrackSettings() | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * for tracks that support simulcasting, adjust subscribed quality | ||
| 61 | + * | ||
| 62 | + * this indicates the highest quality the client can accept. if network bandwidth does not | ||
| 63 | + * allow, server will automatically reduce quality to optimize for uninterrupted video | ||
| 64 | + */ | ||
| 65 | + fun setVideoQuality(quality: LivekitRtc.VideoQuality) { | ||
| 66 | + videoQuality = quality | ||
| 67 | + sendUpdateTrackSettings() | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + private fun sendUpdateTrackSettings() { | ||
| 71 | + val participant = this.participant.get() as? RemoteParticipant ?: return | ||
| 72 | + | ||
| 73 | + participant.rtcClient.sendUpdateTrackSettings(sid, disabled, videoQuality) | ||
| 74 | + } | ||
| 75 | +} |
| 1 | package io.livekit.android.room.track | 1 | package io.livekit.android.room.track |
| 2 | 2 | ||
| 3 | +import io.livekit.android.room.participant.Participant | ||
| 3 | import livekit.LivekitModels | 4 | import livekit.LivekitModels |
| 5 | +import java.lang.ref.WeakReference | ||
| 4 | 6 | ||
| 5 | -open class TrackPublication(info: LivekitModels.TrackInfo, track: Track? = null) { | 7 | +open class TrackPublication(info: LivekitModels.TrackInfo, track: Track?, participant: Participant?) { |
| 6 | var track: Track? = track | 8 | var track: Track? = track |
| 7 | internal set | 9 | internal set |
| 8 | var name: String | 10 | var name: String |
| @@ -11,14 +13,21 @@ open class TrackPublication(info: LivekitModels.TrackInfo, track: Track? = null) | @@ -11,14 +13,21 @@ open class TrackPublication(info: LivekitModels.TrackInfo, track: Track? = null) | ||
| 11 | private set | 13 | private set |
| 12 | var kind: LivekitModels.TrackType | 14 | var kind: LivekitModels.TrackType |
| 13 | private set | 15 | private set |
| 14 | - var muted: Boolean | ||
| 15 | - private set | 16 | + open var muted: Boolean = false |
| 17 | + internal set | ||
| 18 | + open val subscribed: Boolean | ||
| 19 | + get() { | ||
| 20 | + return track != null | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + var participant: WeakReference<Participant>; | ||
| 16 | 24 | ||
| 17 | init { | 25 | init { |
| 18 | sid = info.sid | 26 | sid = info.sid |
| 19 | name = info.name | 27 | name = info.name |
| 20 | kind = info.type | 28 | kind = info.type |
| 21 | muted = info.muted | 29 | muted = info.muted |
| 30 | + this.participant = WeakReference(participant) | ||
| 22 | } | 31 | } |
| 23 | 32 | ||
| 24 | fun updateFromInfo(info: LivekitModels.TrackInfo) { | 33 | fun updateFromInfo(info: LivekitModels.TrackInfo) { |
| @@ -26,7 +35,6 @@ open class TrackPublication(info: LivekitModels.TrackInfo, track: Track? = null) | @@ -26,7 +35,6 @@ open class TrackPublication(info: LivekitModels.TrackInfo, track: Track? = null) | ||
| 26 | name = info.name | 35 | name = info.name |
| 27 | kind = info.type | 36 | kind = info.type |
| 28 | 37 | ||
| 29 | - // TODO: forward mute status to listener | ||
| 30 | muted = info.muted | 38 | muted = info.muted |
| 31 | } | 39 | } |
| 32 | } | 40 | } |
| @@ -30,7 +30,7 @@ class ParticipantItem( | @@ -30,7 +30,7 @@ class ParticipantItem( | ||
| 30 | remoteParticipant.listener = object : ParticipantListener { | 30 | remoteParticipant.listener = object : ParticipantListener { |
| 31 | override fun onTrackSubscribed( | 31 | override fun onTrackSubscribed( |
| 32 | track: Track, | 32 | track: Track, |
| 33 | - publication: TrackPublication, | 33 | + publication: RemoteTrackPublication, |
| 34 | participant: RemoteParticipant | 34 | participant: RemoteParticipant |
| 35 | ) { | 35 | ) { |
| 36 | if (track is VideoTrack) { | 36 | if (track is VideoTrack) { |
-
请 注册 或 登录 后发表评论