133 lines
5.1 KiB
Markdown
133 lines
5.1 KiB
Markdown
# Исправление: Отправка видео на сервер
|
||
|
||
## Проблема
|
||
Приложение показывало превью камеры локально, но **видео вообще не отправлялось на сервер**.
|
||
|
||
### Анализ логов
|
||
Из `logcat` было видно:
|
||
- ✓ WebSocket подключился успешно: `Connected! Response code=101`
|
||
- ✓ Сервер ответил: `Message received: {"error": "Invalid room or password"}`
|
||
- ❌ Но фреймы не отправлялись: в логах нет сообщений о `sendBinary`
|
||
- ❌ Функция `StreamViewModel.sendVideoFrame()` вообще не вызывалась
|
||
|
||
## Корень проблемы
|
||
|
||
### 1. CameraManager не обрабатывал фреймы
|
||
Файл `CameraManager.kt` только показывал превью, но не захватывал видео фреймы.
|
||
- Использовался только `Preview` use case для отображения
|
||
- Отсутствовал `ImageAnalysis` use case для захвата фреймов
|
||
|
||
### 2. Нет связи между камерой и ViewModel
|
||
`MainActivity.kt` запускал камеру, но не передавал фреймы в `ViewModel`:
|
||
```kotlin
|
||
// ДО: просто стартует камеру без callback
|
||
cameraManager.startCamera(lifecycleOwner, pv.surfaceProvider, onError)
|
||
|
||
// НУЖНО: передать фреймы в ViewModel
|
||
cameraManager.startCamera(lifecycleOwner, pv.surfaceProvider, onError,
|
||
onFrame = { frameData -> viewModel.sendVideoFrame(frameData) }
|
||
)
|
||
```
|
||
|
||
### 3. Проблемы с отправкой бинарных данных
|
||
`WebSocketManager.sendBinary()` использовал рефлексию вместо стандартного API:
|
||
```kotlin
|
||
// ДО: сложная рефлексия
|
||
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` для захвата видео фреймов:
|
||
```kotlin
|
||
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 для передачи фреймов:
|
||
```kotlin
|
||
cameraManager.startCamera(
|
||
lifecycleOwner,
|
||
pv.surfaceProvider,
|
||
onError = { err -> Log.e("CameraManager", "Camera error: $err") },
|
||
onFrame = { frameData ->
|
||
viewModel.sendVideoFrame(frameData)
|
||
}
|
||
)
|
||
```
|
||
|
||
### 3. ✅ Исправлен WebSocketManager
|
||
Заменена рефлексия на стандартный API:
|
||
```kotlin
|
||
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"
|
||
|
||
## Проверка
|
||
|
||
После исправления в логах должны появиться:
|
||
1. При подключении:
|
||
```
|
||
WebSocket: Connected! Response code=101
|
||
CameraManager: Camera started successfully with video streaming
|
||
StreamViewModel: Connected to server
|
||
```
|
||
|
||
2. При потоке видео:
|
||
```
|
||
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.
|
||
|