Compare commits

..

1 Commits

Author SHA1 Message Date
3d3f8710f2 feat: use camerax with webrtc lib 2025-04-01 08:20:16 +02:00
2 changed files with 24 additions and 38 deletions

View File

@ -5,6 +5,7 @@ import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.camera.core.ImageAnalysis
import androidx.camera.view.CameraController import androidx.camera.view.CameraController
import androidx.camera.view.LifecycleCameraController import androidx.camera.view.LifecycleCameraController
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -15,26 +16,29 @@ import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.example.tvcontroller.ui.theme.TVControllerTheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.example.tvcontroller.services.BluetoothService import com.example.tvcontroller.services.BluetoothService
import com.example.tvcontroller.services.CameraService import com.example.tvcontroller.services.CameraService
import com.example.tvcontroller.services.ControllerService import com.example.tvcontroller.services.ControllerService
import com.example.tvcontroller.services.DeviceService import com.example.tvcontroller.services.DeviceService
import com.example.tvcontroller.ui.theme.TVControllerTheme
import com.example.tvcontroller.ui.views.CameraView import com.example.tvcontroller.ui.views.CameraView
import com.example.tvcontroller.ui.views.RemoteView import com.example.tvcontroller.ui.views.RemoteView
import com.example.tvcontroller.ui.views.SettingsView import com.example.tvcontroller.ui.views.SettingsView
import com.example.tvcontroller.webrtc.CameraXCapturer
import com.example.tvcontroller.webrtc.RtcPeerConnection import com.example.tvcontroller.webrtc.RtcPeerConnection
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -67,10 +71,6 @@ class MainActivity : ComponentActivity() {
cameraService = CameraService(applicationContext) cameraService = CameraService(applicationContext)
controllerService = ControllerService(applicationContext, bluetoothService) controllerService = ControllerService(applicationContext, bluetoothService)
checkPermissions() checkPermissions()
lifecycleScope.launch(Dispatchers.IO) {
deviceService.initialize()
}
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
TVControllerTheme { TVControllerTheme {
@ -164,7 +164,8 @@ fun TvControllerApp(
composable(route = Screen.Settings.name) { composable(route = Screen.Settings.name) {
SettingsView( SettingsView(
deviceService = deviceService, deviceService = deviceService,
bluetoothService = bluetoothService bluetoothService = bluetoothService,
rtcPeerConnection = rtcPeerConnection
) )
} }
} }

View File

@ -10,13 +10,10 @@ import io.ktor.client.call.body
import io.ktor.client.plugins.cookies.HttpCookies import io.ktor.client.plugins.cookies.HttpCookies
import io.ktor.client.plugins.websocket.WebSockets import io.ktor.client.plugins.websocket.WebSockets
import io.ktor.client.plugins.websocket.webSocket import io.ktor.client.plugins.websocket.webSocket
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.cookie
import io.ktor.client.request.headers import io.ktor.client.request.headers
import io.ktor.client.request.request import io.ktor.client.request.request
import io.ktor.client.request.setBody import io.ktor.client.request.setBody
import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.HttpResponse
import io.ktor.http.Cookie
import io.ktor.http.HttpMethod import io.ktor.http.HttpMethod
import io.ktor.websocket.Frame import io.ktor.websocket.Frame
import io.ktor.websocket.readText import io.ktor.websocket.readText
@ -28,18 +25,15 @@ private const val TAG = "DeviceService"
class DeviceService(private val context: Context) { class DeviceService(private val context: Context) {
private var client = HttpClient(CIO) { private var client = HttpClient(CIO) {
install(HttpCookies)
install(WebSockets) install(WebSockets)
} }
private var serverAddress: String = "" private var serverAddress: String = ""
private var token: String = "" private var token: String = ""
private var deviceId: String = "" private var deviceId: String = ""
suspend fun initialize() { init {
loadPreferences() loadPreferences()
if (token.isEmpty()) return
getIntegration()?.let {
connect()
}
} }
suspend fun registerIntegration(name: String, code: String) { suspend fun registerIntegration(name: String, code: String) {
@ -50,14 +44,12 @@ class DeviceService(private val context: Context) {
token = "" token = ""
deviceId = "" deviceId = ""
try { try {
val response: HttpResponse = val response: HttpResponse = client.request("http://$serverAddress/api/integrations/register") {
client.request("http://$serverAddress/api/integrations/register") {
method = HttpMethod.Post method = HttpMethod.Post
setBody(requestJson.toString()) setBody(requestJson.toString())
headers { headers {
append("Content-Type", "application/json") append("Content-Type", "application/json")
} }
cookie(name = "token", value = token)
} }
val body: String = response.body() val body: String = response.body()
@ -86,7 +78,6 @@ class DeviceService(private val context: Context) {
headers { headers {
append("Authorization", "Bearer $token") append("Authorization", "Bearer $token")
} }
cookie(name = "token", value = token)
} }
val body: String = response.body() val body: String = response.body()
@ -129,17 +120,11 @@ class DeviceService(private val context: Context) {
fun connect() { fun connect() {
Log.i(TAG, "Connecting to websocket at $serverAddress") Log.i(TAG, "Connecting to websocket at $serverAddress")
runBlocking { runBlocking {
// split server address into host and port
val (host, port) = serverAddress.split(":") val (host, port) = serverAddress.split(":")
// if no port is specified, assume 80
val portInt = if (port.isEmpty()) 80 else port.toInt() val portInt = if (port.isEmpty()) 80 else port.toInt()
client.webSocket( client.webSocket(method = HttpMethod.Get, host = host, port = portInt, path = "/ws") {
method = HttpMethod.Get,
host = host,
port = portInt,
path = "/ws",
request = {
cookie(name = "token", value = token)
}
) {
Log.i(TAG, "Listening for incoming websocket messages") Log.i(TAG, "Listening for incoming websocket messages")
while (true) { while (true) {
val frame = incoming.receive() val frame = incoming.receive()