Skip to content

Commit e76ffa0

Browse files
authored
fix: video view (#24)
* fix android video view * fix ios video view * remove unused arg
1 parent b927bf6 commit e76ffa0

8 files changed

Lines changed: 95 additions & 263 deletions

File tree

chime-sdk/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ plugins {
1212
}
1313

1414
group = "com.wannaverse"
15-
version = "0.4.0"
15+
version = "0.4.1"
1616

1717
kotlin {
1818
androidTarget {

chime-sdk/chime_sdk.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |spec|
22
spec.name = 'chime_sdk'
3-
spec.version = '0.4.0'
3+
spec.version = '0.4.1'
44
spec.homepage = 'https://github.com/WannaverseOfficial/kmp-chime-sdk'
55
spec.source = { :http=> ''}
66
spec.authors = ''

chime-sdk/src/androidMain/kotlin/com/wannaverse/chimesdk/ChimeSDK.android.kt

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package com.wannaverse.chimesdk
33
import android.content.Context
44
import android.hardware.camera2.CameraManager
55
import androidx.compose.runtime.Composable
6+
import androidx.compose.runtime.remember
67
import androidx.compose.ui.Modifier
8+
import androidx.compose.ui.viewinterop.AndroidView
79
import com.amazonaws.services.chime.sdk.meetings.analytics.DefaultEventAnalyticsController
810
import com.amazonaws.services.chime.sdk.meetings.analytics.DefaultMeetingStatsCollector
911
import com.amazonaws.services.chime.sdk.meetings.audiovideo.audio.activespeakerpolicy.DefaultActiveSpeakerPolicy
@@ -20,7 +22,6 @@ import com.amazonaws.services.chime.sdk.meetings.session.MeetingSessionCredentia
2022
import com.amazonaws.services.chime.sdk.meetings.session.MeetingSessionURLs
2123
import com.amazonaws.services.chime.sdk.meetings.utils.logger.ConsoleLogger
2224
import com.amazonaws.services.chime.sdk.meetings.utils.logger.LogLevel
23-
import com.wannaverse.chimesdk.composables.VideoTileView
2425

2526
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
2627
actual class ChimeSDK(
@@ -71,7 +72,12 @@ actual class ChimeSDK(
7172
val eglCoreFactory = DefaultEglCoreFactory()
7273

7374
val meetingSession =
74-
DefaultMeetingSession(meetingSessionConfiguration, logger, appContext, eglCoreFactory)
75+
DefaultMeetingSession(
76+
meetingSessionConfiguration,
77+
logger,
78+
appContext,
79+
eglCoreFactory
80+
)
7581

7682
return ChimeSDK(meetingSession, eventAnalyticsController, eglCoreFactory)
7783
}
@@ -191,29 +197,23 @@ actual class ChimeSDK(
191197
}
192198

193199
actual fun leaveMeeting() {
194-
try {
195-
if (cameraOn || cameraCaptureSource != null) {
196-
cameraCaptureSource?.stop()
197-
meetingSession.audioVideo.stopLocalVideo()
198-
cameraOn = false
199-
cameraCaptureSource = null
200-
}
201-
202-
meetingSession.audioVideo.removeRealtimeObserver(realTimeObserver)
203-
meetingSession.audioVideo.removeDeviceChangeObserver(deviceObserver)
204-
meetingSession.audioVideo.removeVideoTileObserver(videoTileObserver)
205-
meetingSession.audioVideo.removeAudioVideoObserver(audioVideoObserver)
206-
meetingSession.audioVideo.removeActiveSpeakerObserver(activeSpeakerObserver)
207-
dataMessageObserver.clearListeners()
208-
209-
meetingSession.audioVideo.stopRemoteVideo()
210-
meetingSession.audioVideo.realtimeLocalMute()
211-
meetingSession.audioVideo.stop()
212-
} catch (e: Exception) {
213-
e.printStackTrace()
200+
if (cameraOn || cameraCaptureSource != null) {
201+
cameraCaptureSource?.stop()
202+
meetingSession.audioVideo.stopLocalVideo()
203+
cameraOn = false
204+
cameraCaptureSource = null
214205
}
215206

216-
videoTileObserver.clearAll()
207+
meetingSession.audioVideo.removeRealtimeObserver(realTimeObserver)
208+
meetingSession.audioVideo.removeDeviceChangeObserver(deviceObserver)
209+
meetingSession.audioVideo.removeVideoTileObserver(videoTileObserver)
210+
meetingSession.audioVideo.removeAudioVideoObserver(audioVideoObserver)
211+
meetingSession.audioVideo.removeActiveSpeakerObserver(activeSpeakerObserver)
212+
dataMessageObserver.clearListeners()
213+
214+
meetingSession.audioVideo.stopRemoteVideo()
215+
meetingSession.audioVideo.realtimeLocalMute()
216+
meetingSession.audioVideo.stop()
217217
}
218218

219219
actual fun startLocalVideo() {
@@ -254,23 +254,28 @@ actual class ChimeSDK(
254254
}
255255

256256
@Composable
257-
actual fun LocalVideoView(modifier: Modifier, cameraFacing: CameraFacing, isOnTop: Boolean) =
258-
VideoTileView(
259-
tileId = videoTileObserver.localTileId!!,
257+
actual fun LocalVideoView(cameraFacing: CameraFacing, modifier: Modifier) {
258+
val mirror = remember(cameraFacing) { cameraFacing == CameraFacing.FRONT }
259+
260+
AndroidView(
261+
factory = {
262+
videoTileObserver.localRenderView.apply { this.mirror = mirror }
263+
},
260264
modifier = modifier,
261-
cameraFacing = cameraFacing,
262-
isOnTop = isOnTop,
263-
meetingSession = meetingSession,
264-
videoTileObserverImpl = videoTileObserver
265+
update = {
266+
it.mirror = mirror
267+
}
265268
)
269+
}
266270

267271
@Composable
268-
actual fun RemoteVideoView(modifier: Modifier, tileId: Int, isOnTop: Boolean) = VideoTileView(
269-
tileId = tileId,
272+
actual fun RemoteVideoView(tileId: Int, modifier: Modifier) = AndroidView(
273+
factory = {
274+
videoTileObserver.getRemoteRenderView(tileId)
275+
?: throw IllegalStateException("Remote view for tile $tileId not found")
276+
},
270277
modifier = modifier,
271-
isOnTop = isOnTop,
272-
meetingSession = meetingSession,
273-
videoTileObserverImpl = videoTileObserver
278+
update = {}
274279
)
275280

276281
actual fun sendRealtimeMessage(topic: String, data: String, lifetimeMs: Long) =
@@ -283,7 +288,8 @@ actual class ChimeSDK(
283288
val source = cameraCaptureSource ?: return
284289

285290
val previous = currentCameraFacing
286-
currentCameraFacing = if (currentCameraFacing == CameraFacing.FRONT) CameraFacing.BACK else CameraFacing.FRONT
291+
currentCameraFacing =
292+
if (currentCameraFacing == CameraFacing.FRONT) CameraFacing.BACK else CameraFacing.FRONT
287293

288294
val cm = appContext.getSystemService(Context.CAMERA_SERVICE) as CameraManager
289295
val devices = MediaDevice.listVideoDevices(cm)

chime-sdk/src/androidMain/kotlin/com/wannaverse/chimesdk/VideoTileObserverImpl.kt

Lines changed: 14 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.wannaverse.chimesdk
22

33
import com.amazonaws.services.chime.sdk.meetings.audiovideo.video.VideoTileObserver
44
import com.amazonaws.services.chime.sdk.meetings.audiovideo.video.VideoTileState
5+
import com.amazonaws.services.chime.sdk.meetings.audiovideo.video.gl.TextureRenderView
56
import com.amazonaws.services.chime.sdk.meetings.session.MeetingSession
67

78
class VideoTileObserverImpl(
@@ -11,92 +12,36 @@ class VideoTileObserverImpl(
1112
private val onRemoteTileAdded: (Int) -> Unit,
1213
private val onRemoteTileRemoved: () -> Unit
1314
) : VideoTileObserver {
14-
companion object {
15-
private const val LOG_TAG = "VIDEO_TILE_MANAGER"
16-
}
17-
18-
var localTileId: Int? = null
19-
private set
15+
internal val localRenderView = TextureRenderView(appContext)
16+
private val remoteRenderView: MutableMap<Int, TextureRenderView> = mutableMapOf()
2017

21-
private fun logTileInfo(event: String, tileState: VideoTileState) {
22-
println("$LOG_TAG | $event | TileId=${tileState.tileId} | IsLocal=${tileState.isLocalTile} | AttendeeId=${tileState.attendeeId} | Dimensions=${tileState.videoStreamContentWidth}x${tileState.videoStreamContentHeight} | Paused=${tileState.pauseState}")
23-
}
18+
fun getRemoteRenderView(tileId: Int): TextureRenderView? = remoteRenderView[tileId]
2419

2520
override fun onVideoTileAdded(tileState: VideoTileState) {
26-
logTileInfo("TILE_ADDED", tileState)
27-
2821
if (tileState.isLocalTile) {
29-
localTileId = tileState.tileId
22+
meetingSession.audioVideo.bindVideoView(localRenderView, tileState.tileId)
3023
onLocalTileAdded(tileState.tileId)
31-
}
32-
else {
24+
} else {
25+
remoteRenderView[tileState.tileId] = TextureRenderView(appContext)
26+
meetingSession.audioVideo.bindVideoView(remoteRenderView[tileState.tileId]!!, tileState.tileId)
3327
onRemoteTileAdded(tileState.tileId)
3428
}
3529
}
3630

3731
override fun onVideoTileRemoved(tileState: VideoTileState) {
38-
logTileInfo("TILE_REMOVED", tileState)
32+
meetingSession.audioVideo.unbindVideoView(tileState.tileId)
3933

4034
if (tileState.isLocalTile) {
41-
localTileId = null
4235
onLocalTileRemoved()
43-
}
44-
else {
45-
onRemoteTileRemoved()
46-
}
47-
}
48-
49-
override fun onVideoTilePaused(tileState: VideoTileState) {
50-
logTileInfo("TILE_PAUSED", tileState)
51-
52-
if (tileState.isLocalTile) {
53-
println("$LOG_TAG | LOCAL_VIDEO_PAUSED | Local video feed paused (user action or app backgrounded)")
54-
} else {
55-
println("$LOG_TAG | REMOTE_VIDEO_PAUSED | Remote video feed paused (network/bandwidth issues)")
56-
}
57-
}
58-
59-
override fun onVideoTileResumed(tileState: VideoTileState) {
60-
logTileInfo("TILE_RESUMED", tileState)
61-
62-
if (tileState.isLocalTile) {
63-
println("$LOG_TAG | LOCAL_VIDEO_RESUMED | Local video feed resumed (user action or app foregrounded)")
64-
} else {
65-
println("$LOG_TAG | REMOTE_VIDEO_RESUMED | Remote video feed resumed (network/bandwidth improved)")
66-
}
67-
}
68-
69-
override fun onVideoTileSizeChanged(tileState: VideoTileState) {
70-
logTileInfo("TILE_SIZE_CHANGED", tileState)
71-
72-
if (tileState.isLocalTile) {
73-
println("$LOG_TAG | LOCAL_TILE_SIZE_CHANGED | Local tile size changed to ${tileState.videoStreamContentWidth}x${tileState.videoStreamContentHeight}")
7436
} else {
75-
println("$LOG_TAG | REMOTE_TILE_SIZE_CHANGED | Remote tile size changed to ${tileState.videoStreamContentWidth}x${tileState.videoStreamContentHeight}")
37+
remoteRenderView -= tileState.tileId
38+
onRemoteTileRemoved()
7639
}
7740
}
7841

79-
private val boundViews = mutableMapOf<Int, Any>()
80-
81-
fun updateBoundView(tileId: Int, view: Any) = boundViews.set(tileId, view)
82-
83-
fun isAlreadyBound(tileId: Int, view: Any): Boolean = boundViews[tileId] === view
42+
override fun onVideoTilePaused(tileState: VideoTileState) {}
8443

85-
fun clearBoundView(tileId: Int) = boundViews.remove(tileId)
44+
override fun onVideoTileResumed(tileState: VideoTileState) {}
8645

87-
fun clearAll() {
88-
println("VIDEO_TILE_VIEW | clearAll | Unbinding all video tiles (${boundViews.size})")
89-
90-
boundViews.forEach { (tileId, _) ->
91-
try {
92-
println("VIDEO_TILE_VIEW | clearAll | Unbinding tile $tileId")
93-
meetingSession.audioVideo.unbindVideoView(tileId)
94-
} catch (e: Exception) {
95-
println("VIDEO_TILE_VIEW | clearAll | Failed to unbind tile $tileId: ${e.message}")
96-
}
97-
}
98-
99-
boundViews.clear()
100-
localTileId = null
101-
}
46+
override fun onVideoTileSizeChanged(tileState: VideoTileState) {}
10247
}

chime-sdk/src/androidMain/kotlin/com/wannaverse/chimesdk/composables/VideoTileView.kt

Lines changed: 0 additions & 59 deletions
This file was deleted.

chime-sdk/src/commonMain/kotlin/com/wannaverse/chimesdk/ChimeSDK.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,11 @@ expect class ChimeSDK {
9191

9292
/** Composable that renders the local camera preview. */
9393
@Composable
94-
fun LocalVideoView(modifier: Modifier, cameraFacing: CameraFacing, isOnTop: Boolean)
94+
fun LocalVideoView(cameraFacing: CameraFacing, modifier: Modifier = Modifier)
9595

9696
/** Composable that renders a remote participant's video tile. */
9797
@Composable
98-
fun RemoteVideoView(modifier: Modifier, tileId: Int, isOnTop: Boolean)
98+
fun RemoteVideoView(tileId: Int, modifier: Modifier = Modifier)
9999

100100
/**
101101
* Broadcasts a real-time data message on [topic].

0 commit comments

Comments
 (0)