5.1 KiB
5.1 KiB
Исправление: Отправка видео на сервер
Проблема
Приложение показывало превью камеры локально, но видео вообще не отправлялось на сервер.
Анализ логов
Из logcat было видно:
- ✓ WebSocket подключился успешно:
Connected! Response code=101 - ✓ Сервер ответил:
Message received: {"error": "Invalid room or password"} - ❌ Но фреймы не отправлялись: в логах нет сообщений о
sendBinary - ❌ Функция
StreamViewModel.sendVideoFrame()вообще не вызывалась
Корень проблемы
1. CameraManager не обрабатывал фреймы
Файл CameraManager.kt только показывал превью, но не захватывал видео фреймы.
- Использовался только
Previewuse case для отображения - Отсутствовал
ImageAnalysisuse case для захвата фреймов
2. Нет связи между камерой и ViewModel
MainActivity.kt запускал камеру, но не передавал фреймы в ViewModel:
// ДО: просто стартует камеру без callback
cameraManager.startCamera(lifecycleOwner, pv.surfaceProvider, onError)
// НУЖНО: передать фреймы в ViewModel
cameraManager.startCamera(lifecycleOwner, pv.surfaceProvider, onError,
onFrame = { frameData -> viewModel.sendVideoFrame(frameData) }
)
3. Проблемы с отправкой бинарных данных
WebSocketManager.sendBinary() использовал рефлексию вместо стандартного API:
// ДО: сложная рефлексия
val byteStringClass = Class.forName("okhttp3.ByteString")
val ofMethod = byteStringClass.getMethod("of", ByteArray::class.java)
// ... и так далее
// ПОСЛЕ: простой и надёжный API
val byteString = ByteString.of(*data)
webSocket?.send(byteString)
Решение
1. ✅ Обновлен CameraManager
Добавлен ImageAnalysis для захвата видео фреймов:
val imageAnalysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
.build()
.apply {
setAnalyzer(analysisExecutor) { imageProxy ->
processFrame(imageProxy)
}
}
// Добавлена обработка фреймов
private fun processFrame(imageProxy: ImageProxy) {
// Преобразование в ByteArray
val frameData = ByteArray(buffer.remaining())
buffer.get(frameData)
// Отправка через callback
onFrameAvailable?.invoke(frameData)
}
2. ✅ Обновлена MainActivity
Добавлен callback для передачи фреймов:
cameraManager.startCamera(
lifecycleOwner,
pv.surfaceProvider,
onError = { err -> Log.e("CameraManager", "Camera error: $err") },
onFrame = { frameData ->
viewModel.sendVideoFrame(frameData)
}
)
3. ✅ Исправлен WebSocketManager
Заменена рефлексия на стандартный API:
import okhttp3.ByteString
fun sendBinary(data: ByteArray) {
try {
val byteString = ByteString.of(*data)
webSocket?.send(byteString)
Log.d("WebSocket", "Binary data sent: ${data.size} bytes")
} catch (e: Exception) {
Log.e("WebSocket", "Binary send error: ${e.message}")
onError(e.message ?: "Failed to send binary data")
}
}
4. ✅ Улучшено логирование
Добавлены логи для отслеживания передачи:
CameraManager: "Processing X frames/5s, sending to server"StreamViewModel: "FPS: X, Total bytes sent: Y"WebSocket: "Binary data sent: X bytes"
Проверка
После исправления в логах должны появиться:
-
При подключении:
WebSocket: Connected! Response code=101 CameraManager: Camera started successfully with video streaming StreamViewModel: Connected to server -
При потоке видео:
CameraManager: Processing 25 frames/5s, sending to server WebSocket: Binary data sent: 12345 bytes StreamViewModel: FPS: 25, Total bytes sent: 308640
Файлы изменены
- ✅
CameraManager.kt- Добавлен ImageAnalysis и обработка фреймов - ✅
MainActivity.kt- Добавлена передача фреймов в ViewModel - ✅
WebSocketManager.kt- Исправлена отправка бинарных данных - ✅
StreamViewModel.kt- Улучшено логирование
Результат
Теперь видео из камеры будет отправляться на сервер сразу после успешного подключения WebSocket.