diff --git a/app/build.gradle b/app/build.gradle index 36c40df0..ca7660b4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -273,7 +273,7 @@ dependencies { implementation "com.github.netless-io:sync-player-android:1.2.1" } - implementation 'io.agora.rtc:full-sdk:3.7.2.1' + implementation 'io.agora.rtc:full-sdk:4.3.0' implementation 'com.github.agorabuilder:rtm-sdk:1.4.10' // Exoplayer diff --git a/app/src/main/java/io/agora/flat/common/rtc/AgoraRtc.kt b/app/src/main/java/io/agora/flat/common/rtc/AgoraRtc.kt index 72e65b72..ec8b5203 100644 --- a/app/src/main/java/io/agora/flat/common/rtc/AgoraRtc.kt +++ b/app/src/main/java/io/agora/flat/common/rtc/AgoraRtc.kt @@ -5,12 +5,13 @@ import io.agora.flat.data.AppEnv import io.agora.flat.di.interfaces.Logger import io.agora.flat.di.interfaces.RtcApi import io.agora.flat.di.interfaces.StartupInitializer -import io.agora.rtc.Constants -import io.agora.rtc.IRtcEngineEventHandler -import io.agora.rtc.RtcEngine -import io.agora.rtc.models.ChannelMediaOptions -import io.agora.rtc.video.VideoCanvas -import io.agora.rtc.video.VideoEncoderConfiguration +import io.agora.rtc2.ChannelMediaOptions +import io.agora.rtc2.Constants +import io.agora.rtc2.IRtcEngineEventHandler +import io.agora.rtc2.RtcEngine +import io.agora.rtc2.RtcEngineConfig +import io.agora.rtc2.video.VideoCanvas +import io.agora.rtc2.video.VideoEncoderConfiguration import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow @@ -20,11 +21,17 @@ import javax.inject.Singleton @Singleton class AgoraRtc @Inject constructor(val appEnv: AppEnv, val logger: Logger) : RtcApi, StartupInitializer { private lateinit var rtcEngine: RtcEngine - private val mHandler: RTCEventHandler = RTCEventHandler() + private val eventHandler: RTCEventHandler = RTCEventHandler() + private var currentUid = 0 override fun init(context: Context) { try { - rtcEngine = RtcEngine.create(context, appEnv.agoraAppId, mHandler) + val config = RtcEngineConfig().apply { + mContext = context + mAppId = appEnv.agoraAppId + mEventHandler = eventHandler + } + rtcEngine = RtcEngine.create(config) // rtcEngine.setLogFile(FileUtil.initializeLogFile(this)) } catch (e: Exception) { e.printStackTrace() @@ -44,6 +51,7 @@ class AgoraRtc @Inject constructor(val appEnv: AppEnv, val logger: Logger) : Rtc ) ) rtcEngine.adjustRecordingSignalVolume(200) + rtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION) } fun rtcEngine(): RtcEngine { @@ -51,14 +59,22 @@ class AgoraRtc @Inject constructor(val appEnv: AppEnv, val logger: Logger) : Rtc } override fun joinChannel(options: RtcJoinOptions): Int { - val channelMediaOptions = ChannelMediaOptions() - channelMediaOptions.publishLocalVideo = options.videoOpen - channelMediaOptions.publishLocalAudio = options.audioOpen - return rtcEngine.joinChannel(options.token, options.channel, "{}", options.uid, channelMediaOptions) + currentUid = options.uid + logger.i("[RTC] create media options by state: video=${options.videoOpen}, audio=${options.audioOpen}") + val mediaOptions = ChannelMediaOptions().apply { + clientRoleType = + if (options.videoOpen || options.audioOpen) Constants.CLIENT_ROLE_BROADCASTER else Constants.CLIENT_ROLE_AUDIENCE + publishCameraTrack = options.videoOpen + publishMicrophoneTrack = options.audioOpen + autoSubscribeAudio = true + autoSubscribeVideo = true + } + return rtcEngine.joinChannel(options.token, options.channel, options.uid, mediaOptions) } - override fun leaveChannel() { - rtcEngine.leaveChannel() + override fun leaveChannel(): Int { + currentUid = 0 + return rtcEngine.leaveChannel() } override fun enableLocalVideo(enabled: Boolean) { @@ -78,9 +94,12 @@ class AgoraRtc @Inject constructor(val appEnv: AppEnv, val logger: Logger) : Rtc } override fun updateLocalStream(audio: Boolean, video: Boolean) { - // 使用 enableLocalAudio 关闭或开启本地采集后,本地听远端播放会有短暂中断。 - rtcEngine.muteLocalAudioStream(!audio) - rtcEngine.muteLocalVideoStream(!video) + val mediaOptions = ChannelMediaOptions().apply { + clientRoleType = if (audio || video) Constants.CLIENT_ROLE_BROADCASTER else Constants.CLIENT_ROLE_AUDIENCE + publishCameraTrack = video + publishMicrophoneTrack = audio + } + rtcEngine.updateChannelMediaOptions(mediaOptions) } override fun updateRemoteStream(rtcUid: Int, audio: Boolean, video: Boolean) { @@ -99,8 +118,7 @@ class AgoraRtc @Inject constructor(val appEnv: AppEnv, val logger: Logger) : Rtc } override fun onAudioVolumeIndication( - speakers: Array, - totalVolume: Int + speakers: Array, totalVolume: Int ) { val info = speakers.map { AudioVolumeInfo(uid = it.uid, volume = it.volume, vad = it.vad) @@ -109,7 +127,7 @@ class AgoraRtc @Inject constructor(val appEnv: AppEnv, val logger: Logger) : Rtc } override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) { - if (uid == 0) { + if (uid == currentUid) { trySend(RtcEvent.NetworkStatus(getOverallQuality(txQuality, rxQuality))) } } @@ -117,11 +135,31 @@ class AgoraRtc @Inject constructor(val appEnv: AppEnv, val logger: Logger) : Rtc override fun onRtcStats(stats: IRtcEngineEventHandler.RtcStats) { trySend(RtcEvent.LastmileDelay(stats.lastmileDelay)) } + + override fun onPermissionError(permission: Int) { + logger.e("[RTC] permission error: $permission") + } + + override fun onRemoteAudioStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) { + logger.i("[RTC] remote audio state changed: $uid, $state, $reason, $elapsed") + } + + override fun onRemoteVideoStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) { + logger.i("[RTC] remote video state changed: $uid, $state, $reason, $elapsed") + } + + override fun onUserMuteAudio(uid: Int, muted: Boolean) { + logger.i("[RTC] user mute audio: $uid, $muted") + } + + override fun onUserMuteVideo(uid: Int, muted: Boolean) { + logger.i("[RTC] user mute video: $uid, $muted") + } } - mHandler.addListener(listener) + eventHandler.addListener(listener) awaitClose { logger.i("[RTC] rtc event flow closed") - mHandler.removeListener(listener) + eventHandler.removeListener(listener) } } diff --git a/app/src/main/java/io/agora/flat/common/rtc/Misc.kt b/app/src/main/java/io/agora/flat/common/rtc/Misc.kt index 390944ec..f9c169fe 100644 --- a/app/src/main/java/io/agora/flat/common/rtc/Misc.kt +++ b/app/src/main/java/io/agora/flat/common/rtc/Misc.kt @@ -1,6 +1,7 @@ package io.agora.flat.common.rtc -import io.agora.rtc.IRtcEngineEventHandler +import io.agora.rtc2.Constants +import io.agora.rtc2.IRtcEngineEventHandler internal class RTCEventHandler : IRtcEngineEventHandler() { private val listeners = ArrayList() @@ -19,12 +20,22 @@ internal class RTCEventHandler : IRtcEngineEventHandler() { } } + override fun onRejoinChannelSuccess(channel: String, uid: Int, elapsed: Int) { + for (listener in listeners) { + listener.onRejoinChannelSuccess(channel, uid, elapsed) + } + } + override fun onLeaveChannel(stats: RtcStats) { for (listener in listeners) { listener.onLeaveChannel(stats) } } + override fun onConnectionStateChanged(state: Int, reason: Int) { + super.onConnectionStateChanged(state, reason) + } + override fun onFirstRemoteVideoDecoded(uid: Int, width: Int, height: Int, elapsed: Int) { for (listener in listeners) { listener.onFirstRemoteVideoDecoded(uid, width, height, elapsed) @@ -43,7 +54,7 @@ internal class RTCEventHandler : IRtcEngineEventHandler() { } } - override fun onLocalVideoStats(stats: LocalVideoStats) { + override fun onLocalVideoStats(source: Constants.VideoSourceType, stats: LocalVideoStats) { for (listener in listeners) { listener.onLocalVideoStats(stats) } @@ -90,15 +101,47 @@ internal class RTCEventHandler : IRtcEngineEventHandler() { listener.onAudioVolumeIndication(speakers, totalVolume) } } + + override fun onPermissionError(permission: Int) { + for (listener in listeners) { + listener.onPermissionError(permission) + } + } + + override fun onRemoteAudioStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) { + for (listener in listeners) { + listener.onRemoteAudioStateChanged(uid, state, reason, elapsed) + } + } + + override fun onRemoteVideoStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) { + for (listener in listeners) { + listener.onRemoteVideoStateChanged(uid, state, reason, elapsed) + } + } + + override fun onUserMuteAudio(uid: Int, muted: Boolean) { + for (listener in listeners) { + listener.onUserMuteAudio(uid, muted) + } + } + + override fun onUserMuteVideo(uid: Int, muted: Boolean) { + for (listener in listeners) { + listener.onUserMuteVideo(uid, muted) + } + } } internal interface RTCEventListener { fun onFirstRemoteVideoDecoded(uid: Int, width: Int, height: Int, elapsed: Int) {} - fun onLeaveChannel(stats: IRtcEngineEventHandler.RtcStats?) {} - fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {} + fun onRejoinChannelSuccess(channel: String, uid: Int, elapsed: Int) {} + + fun onLeaveChannel(stats: IRtcEngineEventHandler.RtcStats?) {} + fun onUserOffline(uid: Int, reason: Int) {} fun onUserJoined(uid: Int, elapsed: Int) {} @@ -118,4 +161,13 @@ internal interface RTCEventListener { fun onRemoteAudioStats(stats: IRtcEngineEventHandler.RemoteAudioStats) {} fun onAudioVolumeIndication(speakers: Array, totalVolume: Int) {} + fun onPermissionError(permission: Int) {} + + fun onRemoteAudioStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) {} + + fun onRemoteVideoStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) {} + + fun onUserMuteAudio(uid: Int, muted: Boolean) {} + + fun onUserMuteVideo(uid: Int, muted: Boolean) {} } \ No newline at end of file diff --git a/app/src/main/java/io/agora/flat/ui/viewmodel/RtcVideoController.kt b/app/src/main/java/io/agora/flat/common/rtc/RtcVideoController.kt similarity index 96% rename from app/src/main/java/io/agora/flat/ui/viewmodel/RtcVideoController.kt rename to app/src/main/java/io/agora/flat/common/rtc/RtcVideoController.kt index 8aebf06a..c0351403 100644 --- a/app/src/main/java/io/agora/flat/ui/viewmodel/RtcVideoController.kt +++ b/app/src/main/java/io/agora/flat/common/rtc/RtcVideoController.kt @@ -1,4 +1,4 @@ -package io.agora.flat.ui.viewmodel +package io.agora.flat.common.rtc import android.view.TextureView import android.view.View @@ -6,14 +6,15 @@ import android.widget.FrameLayout import androidx.core.view.isVisible import dagger.hilt.android.scopes.ActivityRetainedScoped import io.agora.flat.di.interfaces.RtcApi -import io.agora.rtc.RtcEngine -import io.agora.rtc.video.VideoCanvas +import io.agora.rtc2.video.VideoCanvas +import io.agora.rtc2.RtcEngine import javax.inject.Inject import kotlin.collections.set @ActivityRetainedScoped class RtcVideoController @Inject constructor(private val rtcApi: RtcApi) { private var textureMap = HashMap() + var shareScreenContainer: FrameLayout? = null var localUid: Int = 0 var shareScreenUid: Int = 0 diff --git a/app/src/main/java/io/agora/flat/di/interfaces/RtcApi.kt b/app/src/main/java/io/agora/flat/di/interfaces/RtcApi.kt index 0c426b2f..73e2283f 100644 --- a/app/src/main/java/io/agora/flat/di/interfaces/RtcApi.kt +++ b/app/src/main/java/io/agora/flat/di/interfaces/RtcApi.kt @@ -2,13 +2,13 @@ package io.agora.flat.di.interfaces import io.agora.flat.common.rtc.RtcEvent import io.agora.flat.common.rtc.RtcJoinOptions -import io.agora.rtc.video.VideoCanvas +import io.agora.rtc2.video.VideoCanvas import kotlinx.coroutines.flow.Flow interface RtcApi { fun joinChannel(options: RtcJoinOptions): Int - fun leaveChannel() + fun leaveChannel(): Int fun enableLocalVideo(enabled: Boolean) diff --git a/app/src/main/java/io/agora/flat/ui/activity/play/ClassRoomViewModel.kt b/app/src/main/java/io/agora/flat/ui/activity/play/ClassRoomViewModel.kt index 511e0d0d..714970f5 100644 --- a/app/src/main/java/io/agora/flat/ui/activity/play/ClassRoomViewModel.kt +++ b/app/src/main/java/io/agora/flat/ui/activity/play/ClassRoomViewModel.kt @@ -59,7 +59,7 @@ import io.agora.flat.ui.manager.RecordManager import io.agora.flat.ui.manager.RoomErrorManager import io.agora.flat.ui.manager.UserManager import io.agora.flat.ui.viewmodel.ChatMessageManager -import io.agora.flat.ui.viewmodel.RtcVideoController +import io.agora.flat.common.rtc.RtcVideoController import io.agora.flat.util.toInviteCodeDisplay import kotlinx.coroutines.async import kotlinx.coroutines.cancel @@ -265,11 +265,19 @@ class ClassRoomViewModel @Inject constructor( private fun joinRtc() { logger.i("[RTC] start join rtc") state.value?.run { + val rtcJoinOptions = RtcJoinOptions( + token = rtcToken, + channel = roomUUID, + uid = rtcUID, + audioOpen = audioOpen, + videoOpen = videoOpen + ) rtcVideoController.setupUid(uid = rtcUID, ssUid = rtcShareScreen.uid) - rtcApi.joinChannel( - RtcJoinOptions(rtcToken, roomUUID, rtcUID, audioOpen = audioOpen, videoOpen = videoOpen) - ).also { - logger.i("[RTC] join rtc result: $it") + rtcApi.joinChannel(rtcJoinOptions).also { result -> + when (result) { + 0 -> logger.i("[RTC] join rtc successful") + else -> logger.w("[RTC] join rtc error: $result") + } } } } diff --git a/app/src/main/java/io/agora/flat/ui/activity/play/RtcComponent.kt b/app/src/main/java/io/agora/flat/ui/activity/play/RtcComponent.kt index 90c3f383..87a19f49 100644 --- a/app/src/main/java/io/agora/flat/ui/activity/play/RtcComponent.kt +++ b/app/src/main/java/io/agora/flat/ui/activity/play/RtcComponent.kt @@ -47,7 +47,7 @@ import io.agora.flat.ui.manager.RoomOverlayManager import io.agora.flat.ui.manager.WindowsDragManager import io.agora.flat.ui.view.PaddingItemDecoration import io.agora.flat.ui.view.UserWindowLayout -import io.agora.flat.ui.viewmodel.RtcVideoController +import io.agora.flat.common.rtc.RtcVideoController import io.agora.flat.util.dp2px import io.agora.flat.util.renderTo import io.agora.flat.util.showToast @@ -66,10 +66,18 @@ class RtcComponent( private val userWindowsLayout: FrameLayout, ) : BaseComponent(activity, rootView) { companion object { - val REQUESTED_PERMISSIONS = arrayOf( - Manifest.permission.RECORD_AUDIO, - Manifest.permission.CAMERA, - ) + fun getRequiredPermissions(): Array { + return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + arrayOf( + Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.BLUETOOTH_CONNECT + ) + } else { + arrayOf( + Manifest.permission.RECORD_AUDIO, + Manifest.permission.CAMERA, + ) + } + } } @EntryPoint @@ -187,12 +195,15 @@ class RtcComponent( is RtcEvent.UserJoined -> lifecycleScope.launch { rtcVideoController.handlerJoined(event.uid) } + is RtcEvent.UserOffline -> lifecycleScope.launch { rtcVideoController.handleOffline(event.uid) } + is RtcEvent.VolumeIndication -> { adapter.updateVolume(event.speakers) } + else -> { } @@ -206,6 +217,7 @@ class RtcComponent( is RewardReceived -> { handleReward(event.userUUID) } + else -> {} } } @@ -271,8 +283,7 @@ class RtcComponent( getViewRect(container, userWindowsBinding.root) } ?: Rect(0, 0, 0, 0) addNewUserWindow( - user = it, - windowUiState = UserWindowUiState( + user = it, windowUiState = UserWindowUiState( centerX = rect.centerX().toFloat(), centerY = rect.centerY().toFloat(), width = rect.width().toFloat(), @@ -288,10 +299,9 @@ class RtcComponent( val needAnimate = toUpdate.any { val a = state[it]!! val b = targetState[it]!! - abs(a.height - b.height) > scaledTouchSlop || - abs(a.width - b.width) > scaledTouchSlop || - abs(a.centerX - b.centerX) > scaledTouchSlop || - abs(a.centerY - b.centerY) > scaledTouchSlop + abs(a.height - b.height) > scaledTouchSlop || abs(a.width - b.width) > scaledTouchSlop || abs(a.centerX - b.centerX) > scaledTouchSlop || abs( + a.centerY - b.centerY + ) > scaledTouchSlop } if (!needAnimate) { windowsDragManager.setWindowMap(targetState) @@ -334,12 +344,15 @@ class RtcComponent( fullScreenBinding.fullAudioOpt, videoListBinding.audioOpt -> userCallOut?.run { viewModel.enableAudio(!it.isSelected, userUUID) } + fullScreenBinding.fullVideoOpt, videoListBinding.videoOpt -> userCallOut?.run { viewModel.enableVideo(!it.isSelected, userUUID) } + fullScreenBinding.exitFullScreen -> { fullScreenAnimator.hide() } + videoListBinding.enterFullScreen -> { hideVideoListOptArea() fullScreenAnimator.show() @@ -441,45 +454,37 @@ class RtcComponent( videoListBinding.videoList.adapter = adapter videoListBinding.videoList.addItemDecoration(PaddingItemDecoration(vertical = activity.dp2px(4))) - videoAreaAnimator = SimpleAnimator( - onUpdate = ::updateVideoContainer, + videoAreaAnimator = SimpleAnimator(onUpdate = ::updateVideoContainer, onShowStart = { videoListBinding.root.isVisible = true }, - onHideEnd = { videoListBinding.root.isVisible = false } - ) - - fullScreenAnimator = SimpleAnimator( - onUpdate = ::updateView, - onShowStart = { - fullScreenBinding.root.isVisible = true - fullScreenBinding.fullVideoView.isVisible = true - userCallOut?.run { - rtcVideoController.enterFullScreen(rtcUID) - rtcVideoController.updateFullScreenVideo(fullScreenBinding.fullVideoView, rtcUID) - - fullScreenBinding.fullVideoDisableLayout.isVisible = !videoOpen - fullScreenBinding.fullScreenAvatar.load(avatarURL) { - crossfade(true) - transformations(CircleCropTransformation()) - } + onHideEnd = { videoListBinding.root.isVisible = false }) + + fullScreenAnimator = SimpleAnimator(onUpdate = ::updateView, onShowStart = { + fullScreenBinding.root.isVisible = true + fullScreenBinding.fullVideoView.isVisible = true + userCallOut?.run { + rtcVideoController.enterFullScreen(rtcUID) + rtcVideoController.updateFullScreenVideo(fullScreenBinding.fullVideoView, rtcUID) + + fullScreenBinding.fullVideoDisableLayout.isVisible = !videoOpen + fullScreenBinding.fullScreenAvatar.load(avatarURL) { + crossfade(true) + transformations(CircleCropTransformation()) } - }, - onShowEnd = { - fullScreenBinding.fullVideoOptArea.isVisible = true - }, - onHideStart = { - fullScreenBinding.fullVideoOptArea.isVisible = false - }, - onHideEnd = { - fullScreenBinding.root.isVisible = false - fullScreenBinding.fullVideoView.isVisible = false - fullScreenBinding.fullVideoDisableLayout.isVisible = false - rtcVideoController.exitFullScreen() - userCallOut?.run { - adapter.updateVideoView(rtcUID) - } - clearCallOutAndNotify() } - ) + }, onShowEnd = { + fullScreenBinding.fullVideoOptArea.isVisible = true + }, onHideStart = { + fullScreenBinding.fullVideoOptArea.isVisible = false + }, onHideEnd = { + fullScreenBinding.root.isVisible = false + fullScreenBinding.fullVideoView.isVisible = false + fullScreenBinding.fullVideoDisableLayout.isVisible = false + rtcVideoController.exitFullScreen() + userCallOut?.run { + adapter.updateVideoView(rtcUID) + } + clearCallOutAndNotify() + }) initUserWindowsLayout() } @@ -585,11 +590,8 @@ class RtcComponent( } private fun checkPermission(actionAfterPermission: () -> Unit) { - val permissions = REQUESTED_PERMISSIONS.filter { permission -> - ContextCompat.checkSelfPermission( - activity, - permission - ) != PackageManager.PERMISSION_GRANTED + val permissions = getRequiredPermissions().filter { permission -> + ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED }.toTypedArray() if (permissions.isEmpty()) { @@ -598,6 +600,7 @@ class RtcComponent( } logger.d("[RTC] checkPermission request $permissions") + activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { it -> val allGranted = it.mapNotNull { it.key }.size == it.size if (allGranted) { @@ -632,11 +635,13 @@ class RtcComponent( ) ) } + DragEvent.ACTION_DRAG_ENTERED -> {} DragEvent.ACTION_DRAG_LOCATION -> { updateCenter(windowsDragManager.currentUUID(), event.x, event.y) showEnterBoardArea() } + DragEvent.ACTION_DROP -> { updateCenter(windowsDragManager.currentUUID(), event.x, event.y) clearDragRectShow() @@ -822,16 +827,13 @@ class RtcComponent( } val r = Rect() - val animator = SimpleAnimator( - onUpdate = { value -> - r.lerp(from, to, value) - windowLayoutMap[uuid]?.renderTo(r) - }, - onShowEnd = { - removeNewUserWindow(uuid) - adapter.updateItemByUuid(uuid) - } - ) + val animator = SimpleAnimator(onUpdate = { value -> + r.lerp(from, to, value) + windowLayoutMap[uuid]?.renderTo(r) + }, onShowEnd = { + removeNewUserWindow(uuid) + adapter.updateItemByUuid(uuid) + }) animator.show() } @@ -861,16 +863,13 @@ class RtcComponent( } ?: return val r = Rect() - val animator = SimpleAnimator( - onUpdate = { value -> - r.lerp(from, to, value) - windowLayoutMap[uuid]?.renderTo(r) - }, - onShowEnd = { - windowLayoutMap[uuid]?.renderTo(to) - updateCenter(uuid, to.centerX().toFloat(), to.centerY().toFloat()) - } - ) + val animator = SimpleAnimator(onUpdate = { value -> + r.lerp(from, to, value) + windowLayoutMap[uuid]?.renderTo(r) + }, onShowEnd = { + windowLayoutMap[uuid]?.renderTo(to) + updateCenter(uuid, to.centerX().toFloat(), to.centerY().toFloat()) + }) animator.show() } @@ -882,21 +881,18 @@ class RtcComponent( } val r = Rect() - val animator = SimpleAnimator( - onUpdate = { value -> - r.lerp(from, to, value) - windowLayoutMap[uuid]?.renderTo(r) - }, - onShowEnd = { - removeNewUserWindow(uuid) - adapter.updateItemByUuid(uuid) - if (fullOnStage) { - syncedState.removeMaximizeWindow(uuid) - } else { - syncedState.removeNormalWindow(uuid) - } + val animator = SimpleAnimator(onUpdate = { value -> + r.lerp(from, to, value) + windowLayoutMap[uuid]?.renderTo(r) + }, onShowEnd = { + removeNewUserWindow(uuid) + adapter.updateItemByUuid(uuid) + if (fullOnStage) { + syncedState.removeMaximizeWindow(uuid) + } else { + syncedState.removeNormalWindow(uuid) } - ) + }) animator.show() } @@ -953,11 +949,10 @@ class RtcComponent( * @param value The value to lerp by. Must be between 0 and 1. */ private fun Rect.lerp(start: Rect, end: Rect, value: Float) { - this.set( - /* left = */ (start.left + (end.left - start.left) * value).toInt(), - /* top = */ (start.top + (end.top - start.top) * value).toInt(), - /* right = */ (start.right + (end.right - start.right) * value).toInt(), - /* bottom = */ (start.bottom + (end.bottom - start.bottom) * value).toInt() + this.set(/* left = */ (start.left + (end.left - start.left) * value).toInt(),/* top = */ + (start.top + (end.top - start.top) * value).toInt(),/* right = */ + (start.right + (end.right - start.right) * value).toInt(),/* bottom = */ + (start.bottom + (end.bottom - start.bottom) * value).toInt() ) } @@ -1025,11 +1020,9 @@ class RtcComponent( rewardAnimationView.alpha = 1 - (time - 1.5f) / 0.5f } } - addListener( - onEnd = { - userWindowsBinding.root.removeView(rewardAnimationView) - } - ) + addListener(onEnd = { + userWindowsBinding.root.removeView(rewardAnimationView) + }) start() } } diff --git a/app/src/main/java/io/agora/flat/ui/manager/WindowsDragManager.kt b/app/src/main/java/io/agora/flat/ui/manager/WindowsDragManager.kt index e8bd3c44..f1d13303 100644 --- a/app/src/main/java/io/agora/flat/ui/manager/WindowsDragManager.kt +++ b/app/src/main/java/io/agora/flat/ui/manager/WindowsDragManager.kt @@ -7,7 +7,7 @@ import dagger.hilt.android.scopes.ActivityScoped import io.agora.flat.common.board.WhiteSyncedState import io.agora.flat.common.board.WindowInfo import io.agora.flat.ui.activity.play.UserWindowUiState -import io.agora.flat.ui.viewmodel.RtcVideoController +import io.agora.flat.common.rtc.RtcVideoController import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/io/agora/flat/ui/viewmodel/CallTestViewModel.kt b/app/src/main/java/io/agora/flat/ui/viewmodel/CallTestViewModel.kt index 746705c1..690fb912 100644 --- a/app/src/main/java/io/agora/flat/ui/viewmodel/CallTestViewModel.kt +++ b/app/src/main/java/io/agora/flat/ui/viewmodel/CallTestViewModel.kt @@ -4,10 +4,10 @@ import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import io.agora.flat.common.rtc.AgoraRtc import io.agora.flat.di.interfaces.RtcApi -import io.agora.rtc.IRtcEngineEventHandler -import io.agora.rtc.IRtcEngineEventHandler.LastmileProbeResult -import io.agora.rtc.RtcEngine -import io.agora.rtc.internal.LastmileProbeConfig +import io.agora.rtc2.IRtcEngineEventHandler +import io.agora.rtc2.IRtcEngineEventHandler.LastmileProbeResult +import io.agora.rtc2.RtcEngine +import io.agora.rtc2.internal.LastmileProbeConfig import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject