88 lines
2.9 KiB
Kotlin
88 lines
2.9 KiB
Kotlin
package calls.presentation
|
|
|
|
import androidx.lifecycle.ViewModel
|
|
import androidx.lifecycle.viewModelScope
|
|
import chats.data.remote.signalr.ChatHubClient
|
|
import chats.data.remote.signalr.ChatEvent
|
|
import calls.data.remote.GroupWebRtcManager
|
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
import kotlinx.coroutines.flow.*
|
|
import kotlinx.coroutines.launch
|
|
import org.webrtc.*
|
|
import javax.inject.Inject
|
|
|
|
data class ParticipantState(
|
|
val userId: String,
|
|
val videoTrack: VideoTrack? = null,
|
|
val isAudioMuted: Boolean = false,
|
|
val isVideoDisabled: Boolean = false
|
|
)
|
|
|
|
data class GroupCallState(
|
|
val chatId: String? = null,
|
|
val participants: Map<String, ParticipantState> = emptyMap(),
|
|
val isMicEnabled: Boolean = true,
|
|
val isCameraEnabled: Boolean = true
|
|
)
|
|
|
|
@HiltViewModel
|
|
class GroupCallViewModel @Inject constructor(
|
|
private val webRtcManager: GroupWebRtcManager,
|
|
private val signalrClient: ChatHubClient
|
|
) : ViewModel() {
|
|
|
|
private val _state = MutableStateFlow(GroupCallState())
|
|
val state: StateFlow<GroupCallState> = _state.asStateFlow()
|
|
|
|
init {
|
|
observeSignalREvents()
|
|
}
|
|
|
|
private fun observeSignalREvents() {
|
|
signalrClient.events.onEach { event ->
|
|
when (event) {
|
|
is ChatEvent.GroupCallUserJoined -> handleUserJoined(event.userId)
|
|
is ChatEvent.GroupCallUserLeft -> handleUserLeft(event.userId)
|
|
is ChatEvent.GroupCallOffer -> handleOffer(event.from, event.offer)
|
|
is ChatEvent.GroupCallAnswer -> handleAnswer(event.from, event.answer)
|
|
// Дополнительные обработчики ICE кандидатов и т.д.
|
|
else -> Unit
|
|
}
|
|
}.launchIn(viewModelScope)
|
|
}
|
|
|
|
private fun handleUserJoined(userId: String) {
|
|
// Создаем PeerConnection для нового участника
|
|
// Логика идентична портированному CallModal.tsx
|
|
_state.update { it.copy(participants = it.participants + (userId to ParticipantState(userId))) }
|
|
}
|
|
|
|
private fun handleUserLeft(userId: String) {
|
|
webRtcManager.removeParticipant(userId)
|
|
_state.update { it.copy(participants = it.participants - userId) }
|
|
}
|
|
|
|
private fun handleOffer(from: String, sdp: String) {
|
|
// Установка RemoteDescription и создание Answer
|
|
}
|
|
|
|
private fun handleAnswer(from: String, sdp: String) {
|
|
// Установка RemoteDescription
|
|
}
|
|
|
|
fun toggleMic() {
|
|
_state.update { it.copy(isMicEnabled = !it.isMicEnabled) }
|
|
// Логика управления AudioTrack
|
|
}
|
|
|
|
fun toggleCamera() {
|
|
_state.update { it.copy(isCameraEnabled = !it.isCameraEnabled) }
|
|
// Логика управления VideoTrack
|
|
}
|
|
|
|
override fun onCleared() {
|
|
super.onCleared()
|
|
webRtcManager.closeAll()
|
|
}
|
|
}
|