init commit

This commit is contained in:
2025-09-28 22:00:44 +09:00
commit 25cb9d9c8f
5877 changed files with 582116 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,256 @@
package com.godeye.android
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.godeye.android.camera.CameraManager
import com.godeye.android.databinding.ActivityMainBinding
import com.godeye.android.network.SocketManager
import com.godeye.android.webrtc.WebRTCManager
import org.webrtc.EglBase
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var socketManager: SocketManager
private lateinit var cameraManager: CameraManager
private lateinit var webRTCManager: WebRTCManager
private lateinit var eglBase: EglBase
private val deviceId by lazy {
Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
}
companion object {
private const val PERMISSION_REQUEST_CODE = 100
private val REQUIRED_PERMISSIONS = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_NETWORK_STATE
)
private const val SERVER_URL = "http://10.0.2.2:3000" // Для эмулятора, для реального устройства укажите IP сервера
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
checkPermissions()
}
private fun checkPermissions() {
val missingPermissions = REQUIRED_PERMISSIONS.filter {
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
}
if (missingPermissions.isNotEmpty()) {
ActivityCompat.requestPermissions(this, missingPermissions.toTypedArray(), PERMISSION_REQUEST_CODE)
} else {
initializeComponents()
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQUEST_CODE) {
val allPermissionsGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
if (allPermissionsGranted) {
initializeComponents()
} else {
showPermissionDeniedDialog()
}
}
}
private fun showPermissionDeniedDialog() {
AlertDialog.Builder(this)
.setTitle("Необходимы разрешения")
.setMessage("Для работы приложения необходим доступ к камере, микрофону и интернету")
.setPositiveButton("OK") { _, _ -> finish() }
.show()
}
private fun initializeComponents() {
try {
// Инициализируем EGL контекст для WebRTC
eglBase = EglBase.create()
// Инициализируем менеджеры
cameraManager = CameraManager(this, eglBase)
webRTCManager = WebRTCManager(this, cameraManager)
socketManager = SocketManager(SERVER_URL)
setupSocketCallbacks()
setupWebRTCCallbacks()
setupUI()
connectToServer()
} catch (e: Exception) {
Log.e("MainActivity", "Error initializing components", e)
Toast.makeText(this, "Ошибка инициализации: ${e.message}", Toast.LENGTH_LONG).show()
}
}
private fun setupSocketCallbacks() {
socketManager.onCameraRequest = { sessionId, operatorId, cameraTypeStr ->
runOnUiThread {
val cameraType = parseCameraType(cameraTypeStr)
showCameraRequestDialog(sessionId, operatorId, cameraType)
}
}
socketManager.onCameraSwitch = { sessionId, cameraTypeStr ->
runOnUiThread {
val cameraType = parseCameraType(cameraTypeStr)
val success = webRTCManager.switchCamera(sessionId, cameraType)
updateCameraStatus(sessionId, if (success) "Камера переключена на: $cameraTypeStr" else "Ошибка переключения камеры")
}
}
socketManager.onCameraDisconnect = { sessionId ->
runOnUiThread {
webRTCManager.closeSession(sessionId)
updateConnectionStatus("Оператор отключился")
}
}
socketManager.onWebRTCAnswer = { sessionId, answer ->
webRTCManager.handleAnswer(sessionId, answer)
}
socketManager.onWebRTCIceCandidate = { sessionId, candidate ->
webRTCManager.handleICECandidate(sessionId, candidate)
}
}
private fun setupWebRTCCallbacks() {
webRTCManager.onOfferCreated = { sessionId, offer ->
socketManager.sendWebRTCOffer(sessionId, offer)
}
webRTCManager.onAnswerCreated = { sessionId, answer ->
socketManager.sendWebRTCAnswer(sessionId, answer)
}
webRTCManager.onICECandidate = { sessionId, candidate ->
socketManager.sendICECandidate(sessionId, candidate)
}
webRTCManager.onConnectionStateChanged = { sessionId, state ->
runOnUiThread {
val statusText = when (state) {
org.webrtc.PeerConnection.PeerConnectionState.CONNECTING -> "Подключение..."
org.webrtc.PeerConnection.PeerConnectionState.CONNECTED -> "Подключено"
org.webrtc.PeerConnection.PeerConnectionState.DISCONNECTED -> "Отключено"
org.webrtc.PeerConnection.PeerConnectionState.FAILED -> "Ошибка подключения"
org.webrtc.PeerConnection.PeerConnectionState.CLOSED -> "Соединение закрыто"
else -> "Неизвестно"
}
updateConnectionStatus("$statusText (Сессия: $sessionId)")
}
}
}
private fun setupUI() {
// Показываем доступные типы камер
val availableTypes = cameraManager.getAvailableCameraTypes()
binding.availableCamerasText.text = "Доступные камеры: ${availableTypes.joinToString(", ")}"
// Показываем Device ID
binding.deviceIdText.text = "Device ID: $deviceId"
// Статус подключения
updateConnectionStatus("Инициализация...")
}
private fun connectToServer() {
val deviceInfo = mapOf(
"model" to android.os.Build.MODEL,
"manufacturer" to android.os.Build.MANUFACTURER,
"androidVersion" to android.os.Build.VERSION.RELEASE,
"appVersion" to BuildConfig.VERSION_NAME
)
socketManager.connect(deviceId, deviceInfo)
updateConnectionStatus("Подключение к серверу...")
}
private fun handleCameraRequest(sessionId: String, operatorId: String, cameraType: String) {
runOnUiThread {
binding.tvStatus.text = "Запрос доступа к камере от оператора: $operatorId"
binding.tvCameraType.text = "Тип камеры: $cameraType"
try {
cameraManager.startCamera(cameraType) { success ->
if (success) {
val streamUrl = webRTCManager.createOffer(sessionId) { offer ->
socketManager.sendWebRTCOffer(sessionId, offer)
}
socketManager.respondToCameraRequest(sessionId, true, streamUrl)
updateConnectionStatus("Трансляция активна")
} else {
socketManager.respondToCameraRequest(sessionId, false, null, "Не удалось запустить камеру")
updateConnectionStatus("Ошибка запуска камеры")
}
}
} catch (e: Exception) {
Log.e("MainActivity", "Error starting camera", e)
socketManager.respondToCameraRequest(sessionId, false, null, e.message)
}
}
}
private fun handleCameraSwitch(sessionId: String, cameraType: String) {
runOnUiThread {
binding.tvCameraType.text = "Переключение на: $cameraType"
cameraManager.switchCamera(cameraType) { success ->
if (success) {
updateConnectionStatus("Камера переключена на $cameraType")
} else {
updateConnectionStatus("Ошибка переключения камеры")
}
}
}
}
private fun handleCameraDisconnect(sessionId: String) {
runOnUiThread {
cameraManager.stopCamera()
webRTCManager.endSession(sessionId)
updateConnectionStatus("Трансляция завершена")
binding.tvCameraType.text = ""
}
}
private fun updateConnectionStatus(status: String) {
runOnUiThread {
binding.tvStatus.text = status
Log.i("MainActivity", "Status: $status")
}
}
private fun setupUI() {
binding.btnDisconnect.setOnClickListener {
socketManager.disconnect()
finish()
}
}
override fun onDestroy() {
super.onDestroy()
cameraManager.release()
webRTCManager.release()
socketManager.disconnect()
}
}