feat: Only show compatible output formats based on encoder

This commit is contained in:
Myzel394 2023-08-09 21:44:12 +02:00
parent b0c036d297
commit 6c16928896
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
5 changed files with 104 additions and 6 deletions

View File

@ -228,6 +228,12 @@ data class AudioRecorderSettings(
return copy(forceExactMaxDuration = forceExactMaxDuration)
}
fun isOutputFormatCompatible(format: Int): Boolean {
val supportedFormats = ENCODER_SUPPORTED_OUTPUT_FORMATS_MAP[getEncoder()]!!
return supportedFormats.contains(format)
}
companion object {
fun getDefaultInstance(): AudioRecorderSettings = AudioRecorderSettings()
val EXAMPLE_MAX_DURATIONS = listOf(
@ -284,5 +290,41 @@ data class AudioRecorderSettings(
6 to "VORBIS",
7 to "OPUS",
)
val ENCODER_SUPPORTED_OUTPUT_FORMATS_MAP: Map<Int, Array<Int>> = mutableMapOf(
MediaRecorder.AudioEncoder.AAC to arrayOf(
MediaRecorder.OutputFormat.THREE_GPP,
MediaRecorder.OutputFormat.MPEG_4,
MediaRecorder.OutputFormat.AAC_ADTS,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) MediaRecorder.OutputFormat.MPEG_2_TS else null,
).filterNotNull().toTypedArray(),
MediaRecorder.AudioEncoder.AAC_ELD to arrayOf(
MediaRecorder.OutputFormat.THREE_GPP,
MediaRecorder.OutputFormat.MPEG_4,
MediaRecorder.OutputFormat.AAC_ADTS,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) MediaRecorder.OutputFormat.MPEG_2_TS else null,
).filterNotNull().toTypedArray(),
MediaRecorder.AudioEncoder.AMR_NB to arrayOf(
MediaRecorder.OutputFormat.THREE_GPP,
MediaRecorder.OutputFormat.AMR_NB,
),
MediaRecorder.AudioEncoder.AMR_WB to arrayOf(
MediaRecorder.OutputFormat.THREE_GPP,
MediaRecorder.OutputFormat.AMR_WB,
),
MediaRecorder.AudioEncoder.HE_AAC to arrayOf(
MediaRecorder.OutputFormat.THREE_GPP,
MediaRecorder.OutputFormat.MPEG_4,
MediaRecorder.OutputFormat.AAC_ADTS,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) MediaRecorder.OutputFormat.MPEG_2_TS else null,
).filterNotNull().toTypedArray(),
MediaRecorder.AudioEncoder.VORBIS to arrayOf(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) MediaRecorder.OutputFormat.OGG else null,
MediaRecorder.OutputFormat.MPEG_4
).filterNotNull().toTypedArray(),
).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaRecorder.AudioEncoder.OPUS, arrayOf(MediaRecorder.OutputFormat.OGG))
}
}.toMap()
}
}

View File

@ -1,5 +1,6 @@
package app.myzel394.alibi.ui.components.SettingsScreen.atoms
import android.media.MediaRecorder
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AudioFile
import androidx.compose.material3.Button
@ -7,9 +8,13 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarVisuals
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@ -19,6 +24,9 @@ import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.db.AudioRecorderSettings
import app.myzel394.alibi.ui.components.atoms.ExampleListRoulette
import app.myzel394.alibi.ui.components.atoms.SettingsTile
import app.myzel394.alibi.ui.utils.IconResource
import com.maxkeppeker.sheets.core.models.base.Header
import com.maxkeppeker.sheets.core.models.base.IconSource
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
@ -35,6 +43,9 @@ fun OutputFormatTile() {
.data
.collectAsState(initial = AppSettings.getDefaultInstance())
.value
val availableOptions = if (settings.audioRecorderSettings.encoder == null)
AudioRecorderSettings.OUTPUT_FORMAT_INDEX_TEXT_MAP.keys.toTypedArray()
else arrayOf(MediaRecorder.OutputFormat.DEFAULT, *AudioRecorderSettings.ENCODER_SUPPORTED_OUTPUT_FORMATS_MAP[settings.audioRecorderSettings.encoder]!!)
fun updateValue(outputFormat: Int?) {
scope.launch {
@ -48,16 +59,23 @@ fun OutputFormatTile() {
ListDialog(
state = showDialog,
header = Header.Default(
title = stringResource(R.string.ui_settings_option_outputFormat_title),
icon = IconSource(
painter = IconResource.fromImageVector(Icons.Default.AudioFile).asPainterResource(),
contentDescription = null,
)
),
selection = ListSelection.Single(
showRadioButtons = true,
options = IntRange(0, 11).map { index ->
options = availableOptions.map { option ->
ListOption(
titleText = AudioRecorderSettings.OUTPUT_FORMAT_INDEX_TEXT_MAP[index]!!,
selected = settings.audioRecorderSettings.outputFormat == index,
titleText = AudioRecorderSettings.OUTPUT_FORMAT_INDEX_TEXT_MAP[option]!!,
selected = settings.audioRecorderSettings.outputFormat == option,
)
}.toList()
) {index, option ->
updateValue(index)
updateValue(availableOptions[index])
},
)
SettingsTile(

View File

@ -16,11 +16,14 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -51,11 +54,13 @@ fun SettingsScreen(
navController: NavController,
audioRecorder: AudioRecorderModel,
) {
val snackbarHostState = remember { SnackbarHostState() }
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
rememberTopAppBarState()
)
Scaffold(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
topBar = {
LargeTopAppBar(
title = {
@ -124,8 +129,8 @@ fun SettingsScreen(
)
BitrateTile()
SamplingRateTile()
OutputFormatTile()
EncoderTile()
OutputFormatTile()
}
}
}

View File

@ -0,0 +1,32 @@
package app.myzel394.alibi.ui.utils
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.painterResource
class IconResource private constructor(
@DrawableRes private val resID: Int?,
private val imageVector: ImageVector?
) {
@Composable
fun asPainterResource(): Painter {
resID?.let {
return painterResource(id = resID)
}
return rememberVectorPainter(image = imageVector!!)
}
companion object {
fun fromDrawableResource(@DrawableRes resID: Int): IconResource {
return IconResource(resID, null)
}
fun fromImageVector(imageVector: ImageVector?): IconResource {
return IconResource(null, imageVector)
}
}
}

View File

@ -52,11 +52,12 @@
<string name="ui_settings_option_bitrate_description">A higher bitrate means better quality but also larger file size</string>
<string name="ui_settings_option_bitrate_explanation">Set the bitrate for the audio recording</string>
<string name="ui_settings_option_outputFormat_title">Output Format</string>
<string name="ui_settings_value_auto_label">Auto</string>
<string name="ui_settings_option_outputFormat_extra_encoderChanged">Encoder has been changed because the current one was incompatible with this output format</string>
<string name="ui_settings_option_samplingRate_title">Sampling rate</string>
<string name="ui_settings_option_samplingRate_description">Define how many samples per second are taken from the audio signal</string>
<string name="ui_settings_option_samplingRate_explanation">Set the sampling rate</string>
<string name="ui_settings_option_encoder_title">Encoder</string>
<string name="ui_settings_value_auto_label">Auto</string>
<string name="ui_audioRecorder_state_paused_title">Recording paused</string>
<string name="ui_audioRecorder_state_paused_description">Audio Recording has been paused</string>
</resources>