mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-09-20 00:35:47 +01:00
Add internal setting to set calling camera to a static fps.
This commit is contained in:
committed by
Cody Henthorne
parent
296fdade07
commit
84c3fd6fd6
+22
@@ -77,6 +77,7 @@ import org.thoughtcrime.securesms.payments.DataExportUtil
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.registration.data.QuickstartCredentialExporter
|
||||
import org.thoughtcrime.securesms.ringrtc.CameraFpsRanges
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
@@ -100,6 +101,8 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
||||
private lateinit var viewModel: InternalSettingsViewModel
|
||||
private var searchMenuItem: MenuItem? = null
|
||||
|
||||
private val cameraFpsRangeDescription: String? by lazy { CameraFpsRanges.captureCameraRangesDescription(requireContext()) }
|
||||
|
||||
private var scrollToPosition: Int = 0
|
||||
private val layoutManager: LinearLayoutManager?
|
||||
get() = recyclerView?.layoutManager as? LinearLayoutManager
|
||||
@@ -836,6 +839,25 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from("Minimum Capture FPS"),
|
||||
summary = DSLSettingsText.from(
|
||||
buildString {
|
||||
append(if (state.callingMinimumCaptureFps > 0) "${state.callingMinimumCaptureFps} fps" else "Default")
|
||||
cameraFpsRangeDescription?.let { append("\n$it") }
|
||||
}
|
||||
),
|
||||
onClick = {
|
||||
promptUserForInt(
|
||||
title = "Minimum Capture FPS",
|
||||
message = "Floor for the camera's capture framerate range. 0 for default logic. Applies on next call start.",
|
||||
initialValue = state.callingMinimumCaptureFps.takeIf { it > 0 }
|
||||
) { minimumFps ->
|
||||
viewModel.setInternalCallingMinimumCaptureFps(minimumFps ?: 0)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
// TODO [alex] -- db access on main thread!
|
||||
|
||||
+1
@@ -26,6 +26,7 @@ data class InternalSettingsState(
|
||||
val callingUseSoftwareVp9Decode: Boolean,
|
||||
val callingEnableSvc: Boolean,
|
||||
val callingStatsIntervalSecs: Int,
|
||||
val callingMinimumCaptureFps: Int,
|
||||
val useBuiltInEmojiSet: Boolean,
|
||||
val emojiVersion: EmojiFiles.Version?,
|
||||
val removeSenderKeyMinimium: Boolean,
|
||||
|
||||
+6
@@ -177,6 +177,11 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setInternalCallingMinimumCaptureFps(minimumFps: Int) {
|
||||
preferenceDataStore.putInt(InternalValues.CALLING_MINIMUM_CAPTURE_FPS, minimumFps)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setUseConversationItemV2Media(enabled: Boolean) {
|
||||
SignalStore.internal.useConversationItemV2Media = enabled
|
||||
refresh()
|
||||
@@ -265,6 +270,7 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
|
||||
callingUseSoftwareVp9Decode = SignalStore.internal.callingUseSoftwareVp9Decode,
|
||||
callingEnableSvc = SignalStore.internal.callingEnableSvc,
|
||||
callingStatsIntervalSecs = SignalStore.internal.callingStatsIntervalSecs,
|
||||
callingMinimumCaptureFps = SignalStore.internal.callingMinimumCaptureFps,
|
||||
useBuiltInEmojiSet = SignalStore.internal.forceBuiltInEmoji,
|
||||
emojiVersion = null,
|
||||
removeSenderKeyMinimium = SignalStore.internal.removeSenderKeyMinimum,
|
||||
|
||||
@@ -33,6 +33,7 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
const val CALLING_USE_SOFTWARE_VP9_DECODE: String = "internal.calling_use_software_vp9_decode"
|
||||
const val CALLING_ENABLE_SVC: String = "internal.calling_enable_svc"
|
||||
const val CALLING_STATS_INTERVAL_SECS: String = "internal.calling_stats_interval_secs"
|
||||
const val CALLING_MINIMUM_CAPTURE_FPS: String = "internal.calling_minimum_capture_fps"
|
||||
const val SHAKE_TO_REPORT: String = "internal.shake_to_report"
|
||||
const val DISABLE_STORAGE_SERVICE: String = "internal.disable_storage_service"
|
||||
const val LAST_SCROLL_POSITION: String = "internal.last_scroll_position"
|
||||
@@ -196,6 +197,11 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
*/
|
||||
var callingStatsIntervalSecs: Int by integerValue(CALLING_STATS_INTERVAL_SECS, 0).defaultForExternalUsers()
|
||||
|
||||
/**
|
||||
* Minimum fps for the camera's capture framerate range. Zero means use default logic
|
||||
*/
|
||||
var callingMinimumCaptureFps: Int by integerValue(CALLING_MINIMUM_CAPTURE_FPS, 0).defaultForExternalUsers()
|
||||
|
||||
var lastScrollPosition: Int by integerValue(LAST_SCROLL_POSITION, 0).defaultForExternalUsers()
|
||||
|
||||
var useConversationItemV2Media by booleanValue(CONVERSATION_ITEM_V2_MEDIA, false).defaultForExternalUsers()
|
||||
|
||||
@@ -12,9 +12,11 @@ import androidx.annotation.Nullable;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.ringrtc.CameraControl;
|
||||
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
|
||||
import org.thoughtcrime.securesms.service.webrtc.RingRtcDynamicConfiguration;
|
||||
import org.webrtc.Camera1Enumerator;
|
||||
import org.webrtc.Camera2Capturer;
|
||||
import org.webrtc.Camera2Enumerator;
|
||||
import org.webrtc.CameraEnumerationAndroid;
|
||||
import org.webrtc.CameraEnumerator;
|
||||
import org.webrtc.CameraVideoCapturer;
|
||||
import org.webrtc.CapturerObserver;
|
||||
@@ -209,6 +211,10 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
|
||||
private void startCapture() {
|
||||
Log.i(TAG, "startCapture()");
|
||||
try {
|
||||
int minimumCaptureFps = RingRtcDynamicConfiguration.getMinimumCaptureFps();
|
||||
CameraEnumerationAndroid.setMinimumFramerateFps(minimumCaptureFps);
|
||||
Log.i(TAG, "startCapture(): minimum capture fps: " + (minimumCaptureFps > 0 ? String.valueOf(minimumCaptureFps) : "default"));
|
||||
|
||||
capturer.startCapture(CAPTURE_WIDTH, CAPTURE_HEIGHT, CAPTURE_FPS);
|
||||
capturing = true;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.thoughtcrime.securesms.ringrtc
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.hardware.camera2.CameraMetadata
|
||||
import android.util.Range
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.signal.core.util.logging.Log
|
||||
|
||||
/**
|
||||
* Exposes [captureCameraRangesDescription], which lists the fps ranges of the front and back camera
|
||||
* that are suitabe for video calls.
|
||||
*/
|
||||
object CameraFpsRanges {
|
||||
|
||||
private val TAG = Log.tag(CameraFpsRanges::class)
|
||||
|
||||
/**
|
||||
* Descriptions of capture ranges, one camera per line, e.g. "Front: [7,30] [15,15] [30,30]".
|
||||
* Only returns fps ranges for the first non-monochrome camera sensor hardware for each direction
|
||||
*/
|
||||
fun captureCameraRangesDescription(context: Context): String? {
|
||||
return forCaptureCameras(context)
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.joinToString("\n") { camera ->
|
||||
"${camera.facing}: ${camera.ranges.joinToString(" ") { "[${it.lower},${it.upper}]" }}"
|
||||
}
|
||||
}
|
||||
|
||||
private fun forCaptureCameras(context: Context): List<CameraRanges> {
|
||||
val cameraManager: CameraManager = ContextCompat.getSystemService(context, CameraManager::class.java) ?: return emptyList()
|
||||
|
||||
return try {
|
||||
val candidates = cameraManager.cameraIdList.filterNot { id ->
|
||||
cameraManager.characteristics(id)
|
||||
?.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
|
||||
?.contains(CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME)
|
||||
?: false
|
||||
}
|
||||
|
||||
listOf(
|
||||
"Front" to CameraMetadata.LENS_FACING_FRONT,
|
||||
"Back" to CameraMetadata.LENS_FACING_BACK
|
||||
).mapNotNull { (label, facing) ->
|
||||
candidates
|
||||
.firstOrNull { cameraManager.characteristics(it)?.get(CameraCharacteristics.LENS_FACING) == facing }
|
||||
?.let { id ->
|
||||
val ranges = cameraManager.characteristics(id)
|
||||
?.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES)
|
||||
?.sortedWith(compareBy({ it.lower }, { it.upper }))
|
||||
?: emptyList()
|
||||
CameraRanges(label, id, ranges)
|
||||
}
|
||||
?.takeIf { it.ranges.isNotEmpty() }
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Unable to read camera fps ranges", e)
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun CameraManager.characteristics(cameraId: String): CameraCharacteristics? {
|
||||
return try {
|
||||
getCameraCharacteristics(cameraId)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Unable to read characteristics for camera $cameraId", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private data class CameraRanges(val facing: String, val cameraId: String, val ranges: List<Range<Int>>)
|
||||
}
|
||||
+5
@@ -82,6 +82,11 @@ object RingRtcDynamicConfiguration {
|
||||
return if (secs != 0) secs else null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getMinimumCaptureFps(): Int {
|
||||
return SignalStore.internal.callingMinimumCaptureFps.coerceAtLeast(0)
|
||||
}
|
||||
|
||||
private fun getSoCInfo(): Pair<String, String> {
|
||||
// 1. Native API Method (Android 12 / API 31+)
|
||||
if (Build.VERSION.SDK_INT >= 31) {
|
||||
|
||||
Reference in New Issue
Block a user