Improve streaming camera controls
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
package com.kimgo.posefit
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import com.kimgo.posefit.sender.CameraFacing
|
||||
import com.kimgo.posefit.sender.WebRtcSenderClient
|
||||
import timber.log.Timber
|
||||
|
||||
class PosefitStreamingService : Service() {
|
||||
|
||||
private var webRtcClient: WebRtcSenderClient? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
createNotificationChannel()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
when (intent?.action) {
|
||||
ACTION_STOP -> {
|
||||
stopStreaming()
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
ACTION_START -> {
|
||||
val signalingUrl = intent.getStringExtra(EXTRA_SIGNALING_URL) ?: DEFAULT_SIGNALING_URL
|
||||
val cameraFacing = intent.getStringExtra(EXTRA_CAMERA_FACING)
|
||||
?.let { runCatching { CameraFacing.valueOf(it) }.getOrNull() }
|
||||
?: CameraFacing.BACK
|
||||
val preferredCameraName = intent.getStringExtra(EXTRA_CAMERA_NAME)
|
||||
|
||||
startForegroundNotification(signalingUrl, cameraFacing, preferredCameraName)
|
||||
startStreaming(signalingUrl, cameraFacing, preferredCameraName)
|
||||
return START_STICKY
|
||||
}
|
||||
else -> {
|
||||
val signalingUrl = getSavedSignalingUrl()
|
||||
val cameraFacing = getSavedCameraFacing()
|
||||
val preferredCameraName = getSavedCameraName()
|
||||
startForegroundNotification(signalingUrl, cameraFacing, preferredCameraName)
|
||||
startStreaming(signalingUrl, cameraFacing, preferredCameraName)
|
||||
return START_STICKY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
override fun onDestroy() {
|
||||
stopStreaming()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun startStreaming(signalingUrl: String, cameraFacing: CameraFacing, preferredCameraName: String?) {
|
||||
Timber.i(
|
||||
"Streaming service start: %s, cameraFacing=%s, preferredCameraName=%s, orientation=landscape",
|
||||
signalingUrl,
|
||||
cameraFacing,
|
||||
preferredCameraName,
|
||||
)
|
||||
webRtcClient?.release()
|
||||
webRtcClient = WebRtcSenderClient(
|
||||
context = applicationContext,
|
||||
signalingUrl = signalingUrl,
|
||||
cameraFacing = cameraFacing,
|
||||
preferredCameraName = preferredCameraName,
|
||||
).also { it.start() }
|
||||
isRunning = true
|
||||
}
|
||||
|
||||
private fun stopStreaming() {
|
||||
Timber.i("Streaming service stop")
|
||||
webRtcClient?.release()
|
||||
webRtcClient = null
|
||||
isRunning = false
|
||||
}
|
||||
|
||||
private fun startForegroundNotification(signalingUrl: String, cameraFacing: CameraFacing, preferredCameraName: String?) {
|
||||
val notification = buildNotification(signalingUrl, cameraFacing, preferredCameraName)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA)
|
||||
} else {
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildNotification(signalingUrl: String, cameraFacing: CameraFacing, preferredCameraName: String?): Notification {
|
||||
val cameraText = when (cameraFacing) {
|
||||
CameraFacing.FRONT -> "前置摄像头"
|
||||
CameraFacing.BACK -> "后置摄像头"
|
||||
}
|
||||
val cameraModeText = preferredCameraName?.let { "$cameraText $it" } ?: "$cameraText 自动最广角"
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Notification.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle("PoseFit 正在推流")
|
||||
.setContentText("$cameraModeText 横屏720p -> $signalingUrl")
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setOngoing(true)
|
||||
.build()
|
||||
} else {
|
||||
Notification.Builder(this)
|
||||
.setContentTitle("PoseFit 正在推流")
|
||||
.setContentText("$cameraModeText 横屏720p -> $signalingUrl")
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setOngoing(true)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return
|
||||
}
|
||||
|
||||
val channel = NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
"PoseFit 推流",
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
)
|
||||
val manager = getSystemService(NotificationManager::class.java)
|
||||
manager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
private fun getSavedSignalingUrl(): String {
|
||||
val prefs = getSharedPreferences("posefit_prefs", Context.MODE_PRIVATE)
|
||||
return prefs.getString("signaling_url", DEFAULT_SIGNALING_URL) ?: DEFAULT_SIGNALING_URL
|
||||
}
|
||||
|
||||
private fun getSavedCameraFacing(): CameraFacing {
|
||||
val prefs = getSharedPreferences("posefit_prefs", Context.MODE_PRIVATE)
|
||||
val value = prefs.getString("camera_facing", CameraFacing.BACK.name)
|
||||
return runCatching { CameraFacing.valueOf(value ?: CameraFacing.BACK.name) }
|
||||
.getOrDefault(CameraFacing.BACK)
|
||||
}
|
||||
|
||||
private fun getSavedCameraName(): String? {
|
||||
val prefs = getSharedPreferences("posefit_prefs", Context.MODE_PRIVATE)
|
||||
return prefs.getString("camera_name", null)?.takeIf { it.isNotBlank() }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CHANNEL_ID = "posefit_streaming"
|
||||
private const val NOTIFICATION_ID = 1001
|
||||
private const val ACTION_START = "com.kimgo.posefit.action.START_STREAMING"
|
||||
private const val ACTION_STOP = "com.kimgo.posefit.action.STOP_STREAMING"
|
||||
private const val EXTRA_SIGNALING_URL = "extra_signaling_url"
|
||||
private const val EXTRA_CAMERA_FACING = "extra_camera_facing"
|
||||
private const val EXTRA_CAMERA_NAME = "extra_camera_name"
|
||||
private const val DEFAULT_SIGNALING_URL = "ws://192.168.2.6:8765"
|
||||
|
||||
@Volatile
|
||||
var isRunning: Boolean = false
|
||||
private set
|
||||
|
||||
fun startIntent(
|
||||
context: Context,
|
||||
signalingUrl: String,
|
||||
cameraFacing: CameraFacing,
|
||||
preferredCameraName: String?
|
||||
): Intent {
|
||||
return Intent(context, PosefitStreamingService::class.java).apply {
|
||||
action = ACTION_START
|
||||
putExtra(EXTRA_SIGNALING_URL, signalingUrl)
|
||||
putExtra(EXTRA_CAMERA_FACING, cameraFacing.name)
|
||||
putExtra(EXTRA_CAMERA_NAME, preferredCameraName)
|
||||
}
|
||||
}
|
||||
|
||||
fun stopIntent(context: Context): Intent {
|
||||
return Intent(context, PosefitStreamingService::class.java).apply {
|
||||
action = ACTION_STOP
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user