debug: Fix microphone not accessible in background

This commit is contained in:
Myzel394 2023-11-25 17:13:28 +01:00
parent 0de720ccf4
commit f6bdd1b345
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
2 changed files with 39 additions and 32 deletions

View File

@ -53,7 +53,7 @@
android:foregroundServiceType="microphone" /> android:foregroundServiceType="microphone" />
<service <service
android:name=".services.VideoService" android:name=".services.VideoService"
android:foregroundServiceType="camera" /> android:foregroundServiceType="camera|microphone" />
<!-- Change locale for Android <= 12 --> <!-- Change locale for Android <= 12 -->
<service <service

View File

@ -16,9 +16,11 @@ import androidx.camera.core.Preview
import androidx.camera.core.Preview.SurfaceProvider import androidx.camera.core.Preview.SurfaceProvider
import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.MediaStoreOutputOptions import androidx.camera.video.MediaStoreOutputOptions
import androidx.camera.video.PendingRecording
import androidx.camera.video.Quality import androidx.camera.video.Quality
import androidx.camera.video.QualitySelector import androidx.camera.video.QualitySelector
import androidx.camera.video.Recorder import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture.withOutput import androidx.camera.video.VideoCapture.withOutput
import androidx.camera.video.VideoRecordEvent import androidx.camera.video.VideoRecordEvent
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
@ -31,13 +33,20 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
class VideoService : LifecycleService() { class VideoService : LifecycleService() {
private var job = SupervisorJob() private var job = SupervisorJob()
private var scope = CoroutineScope(Dispatchers.IO + job) private var scope = CoroutineScope(Dispatchers.IO + job)
private var counter = 0
private lateinit var cycleTimer: ScheduledExecutorService
private var recording: Recording? = null
private fun createMediaStoreOutputOptions(): MediaStoreOutputOptions { private fun createMediaStoreOutputOptions(): MediaStoreOutputOptions {
val name = "CameraX-recording.mp4" val name = "CameraX-recording-$counter.mp4"
val contentValues = ContentValues().apply { val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, name) put(MediaStore.Video.Media.DISPLAY_NAME, name)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@ -68,11 +77,10 @@ class VideoService : LifecycleService() {
this, this,
NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID,
notification, notification,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA + ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
} else { else
0 0,
},
) )
val cameraProviderFuture = ProcessCameraProvider.getInstance(this) val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
@ -89,37 +97,36 @@ class VideoService : LifecycleService() {
// Unbind use cases before rebinding // Unbind use cases before rebinding
cameraProvider?.unbindAll() cameraProvider?.unbindAll()
// Bind use cases to camera // Bind use cases to camera
cameraProvider?.bindToLifecycle(this@VideoService, cameraSelector, videoCapture) cameraProvider?.bindToLifecycle(
this@VideoService,
cameraSelector,
videoCapture
)
val options = createMediaStoreOutputOptions() val options = createMediaStoreOutputOptions()
val recording = videoCapture.output.prepareRecording(this@VideoService, options) cycleTimer = Executors.newSingleThreadScheduledExecutor().also {
.withAudioEnabled() it.scheduleAtFixedRate(
{
val mainHandler = ContextCompat.getMainExecutor(this@VideoService)
val result = recording.start(ContextCompat.getMainExecutor(this@VideoService), {}) mainHandler.execute {
runCatching {
recording?.stop()
}
scope.launch { val r =
delay(15000) videoCapture.output.prepareRecording(this@VideoService, options)
.withAudioEnabled()
result.stop()
// Unbind use cases before rebinding
cameraProvider?.unbindAll()
// Bind use cases to camera
cameraProvider?.bindToLifecycle(this@VideoService, cameraSelector, videoCapture)
delay(5000)
val recording = videoCapture.output.prepareRecording(this@VideoService, options)
.withAudioEnabled()
val result = recording.start(ContextCompat.getMainExecutor(this@VideoService), {})
delay(15000)
result.stop()
stopSelf()
stopForeground(STOP_FOREGROUND_REMOVE)
recording =
r.start(ContextCompat.getMainExecutor(this@VideoService), {})
}
},
0,
10_000,
TimeUnit.MILLISECONDS
)
} }
}, ContextCompat.getMainExecutor(this)) }, ContextCompat.getMainExecutor(this))
} }