mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-07-31 16:49:28 +00:00
feat(MPV): Spatial Audio for ios
This commit is contained in:
parent
24c005fe6c
commit
406ef99cfc
11 changed files with 138 additions and 7 deletions
2
MPVKit
2
MPVKit
|
|
@ -1 +1 @@
|
|||
Subproject commit 97923266e43d52bbca33a911fd6a7f9a1bcf35cb
|
||||
Subproject commit 2e81303b74762424f4187c905d532a716c8e1ff5
|
||||
|
|
@ -70,6 +70,7 @@ actual object PlayerSettingsStorage {
|
|||
private const val iosTargetPrimariesKey = "ios_target_primaries"
|
||||
private const val iosTargetTransferKey = "ios_target_transfer"
|
||||
private const val iosHardwareDecoderModeKey = "ios_hardware_decoder_mode"
|
||||
private const val iosAudioOutputModeKey = "ios_audio_output_mode"
|
||||
private const val iosExtendedDynamicRangeEnabledKey = "ios_extended_dynamic_range_enabled"
|
||||
private const val iosTargetColorspaceHintEnabledKey = "ios_target_colorspace_hint_enabled"
|
||||
private const val iosHdrComputePeakEnabledKey = "ios_hdr_compute_peak_enabled"
|
||||
|
|
@ -129,6 +130,7 @@ actual object PlayerSettingsStorage {
|
|||
iosTargetPrimariesKey,
|
||||
iosTargetTransferKey,
|
||||
iosHardwareDecoderModeKey,
|
||||
iosAudioOutputModeKey,
|
||||
iosExtendedDynamicRangeEnabledKey,
|
||||
iosTargetColorspaceHintEnabledKey,
|
||||
iosHdrComputePeakEnabledKey,
|
||||
|
|
@ -865,6 +867,13 @@ actual object PlayerSettingsStorage {
|
|||
preferences?.edit()?.putString(ProfileScopedKey.of(iosHardwareDecoderModeKey), mode)?.apply()
|
||||
}
|
||||
|
||||
actual fun loadIosAudioOutputMode(): String? =
|
||||
preferences?.getString(ProfileScopedKey.of(iosAudioOutputModeKey), null)
|
||||
|
||||
actual fun saveIosAudioOutputMode(mode: String) {
|
||||
preferences?.edit()?.putString(ProfileScopedKey.of(iosAudioOutputModeKey), mode)?.apply()
|
||||
}
|
||||
|
||||
private fun loadIosBoolean(keyBase: String, defaultValue: Boolean): Boolean? =
|
||||
preferences?.let { sharedPreferences ->
|
||||
val key = ProfileScopedKey.of(keyBase)
|
||||
|
|
@ -994,6 +1003,7 @@ actual object PlayerSettingsStorage {
|
|||
loadIosTargetPrimaries()?.let { put(iosTargetPrimariesKey, encodeSyncString(it)) }
|
||||
loadIosTargetTransfer()?.let { put(iosTargetTransferKey, encodeSyncString(it)) }
|
||||
loadIosHardwareDecoderMode()?.let { put(iosHardwareDecoderModeKey, encodeSyncString(it)) }
|
||||
loadIosAudioOutputMode()?.let { put(iosAudioOutputModeKey, encodeSyncString(it)) }
|
||||
loadIosExtendedDynamicRangeEnabled()?.let { put(iosExtendedDynamicRangeEnabledKey, encodeSyncBoolean(it)) }
|
||||
loadIosTargetColorspaceHintEnabled()?.let { put(iosTargetColorspaceHintEnabledKey, encodeSyncBoolean(it)) }
|
||||
loadIosHdrComputePeakEnabled()?.let { put(iosHdrComputePeakEnabledKey, encodeSyncBoolean(it)) }
|
||||
|
|
@ -1061,6 +1071,7 @@ actual object PlayerSettingsStorage {
|
|||
payload.decodeSyncString(iosTargetPrimariesKey)?.let(::saveIosTargetPrimaries)
|
||||
payload.decodeSyncString(iosTargetTransferKey)?.let(::saveIosTargetTransfer)
|
||||
payload.decodeSyncString(iosHardwareDecoderModeKey)?.let(::saveIosHardwareDecoderMode)
|
||||
payload.decodeSyncString(iosAudioOutputModeKey)?.let(::saveIosAudioOutputMode)
|
||||
payload.decodeSyncBoolean(iosExtendedDynamicRangeEnabledKey)?.let(::saveIosExtendedDynamicRangeEnabled)
|
||||
payload.decodeSyncBoolean(iosTargetColorspaceHintEnabledKey)?.let(::saveIosTargetColorspaceHintEnabled)
|
||||
payload.decodeSyncBoolean(iosHdrComputePeakEnabledKey)?.let(::saveIosHdrComputePeakEnabled)
|
||||
|
|
|
|||
|
|
@ -1560,6 +1560,12 @@
|
|||
<string name="settings_playback_ios_display_color_hint_desc">Let mpv target the active display color space by default.</string>
|
||||
<string name="settings_playback_ios_target_primaries">Target primaries</string>
|
||||
<string name="settings_playback_ios_target_transfer">Target transfer</string>
|
||||
<!-- Playback settings iOS audio output -->
|
||||
<string name="settings_playback_ios_audio_output_section">iOS audio output</string>
|
||||
<string name="settings_playback_ios_audio_output">Audio output</string>
|
||||
<string name="settings_playback_ios_audio_output_auto_desc">Try AVFoundation first, then fall back to AudioUnit.</string>
|
||||
<string name="settings_playback_ios_audio_output_avfoundation_desc">Experimental support for Spatial Audio and multichannel output.</string>
|
||||
<string name="settings_playback_ios_audio_output_audiounit_desc">Use the legacy AudioUnit output.</string>
|
||||
<!-- Debrid Result Management section -->
|
||||
<string name="settings_debrid_section_result_management">Result Management</string>
|
||||
<string name="settings_debrid_max_results">Max results</string>
|
||||
|
|
@ -1660,6 +1666,7 @@
|
|||
<string name="submit_intro_capture">Capture</string>
|
||||
<!-- iOS advanced playback -->
|
||||
<string name="settings_playback_ios_hw_decoder_dialog">Hardware decoder</string>
|
||||
<string name="settings_playback_ios_audio_output_dialog">Audio output</string>
|
||||
<string name="settings_playback_ios_target_primaries_dialog">Target primaries</string>
|
||||
<string name="settings_playback_ios_target_transfer_dialog">Target transfer</string>
|
||||
<!-- Collection editor -->
|
||||
|
|
|
|||
|
|
@ -146,6 +146,15 @@ enum class IosHardwareDecoderMode(
|
|||
Off("no", "Off"),
|
||||
}
|
||||
|
||||
enum class IosAudioOutputMode(
|
||||
val mpvValue: String,
|
||||
val label: String,
|
||||
) {
|
||||
Auto("avfoundation,audiounit,", "Auto"),
|
||||
AvFoundation("avfoundation", "AVFoundation"),
|
||||
AudioUnit("audiounit", "AudioUnit"),
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun IosVideoOutputPreset.localizedLabel(): String = when (this) {
|
||||
IosVideoOutputPreset.NativeEdr -> stringResource(Res.string.player_ios_preset_native_edr_label)
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ data class PlayerSettingsUiState(
|
|||
val iosTargetPrimaries: IosTargetPrimaries = IosTargetPrimaries.Auto,
|
||||
val iosTargetTransfer: IosTargetTransfer = IosTargetTransfer.Auto,
|
||||
val iosHardwareDecoderMode: IosHardwareDecoderMode = IosHardwareDecoderMode.VideoToolbox,
|
||||
val iosAudioOutputMode: IosAudioOutputMode = IosAudioOutputMode.Auto,
|
||||
val iosExtendedDynamicRangeEnabled: Boolean = true,
|
||||
val iosTargetColorspaceHintEnabled: Boolean = true,
|
||||
val iosHdrComputePeakEnabled: Boolean = true,
|
||||
|
|
@ -132,6 +133,7 @@ object PlayerSettingsRepository {
|
|||
private var iosTargetPrimaries = IosTargetPrimaries.Auto
|
||||
private var iosTargetTransfer = IosTargetTransfer.Auto
|
||||
private var iosHardwareDecoderMode = IosHardwareDecoderMode.VideoToolbox
|
||||
private var iosAudioOutputMode = IosAudioOutputMode.Auto
|
||||
private var iosExtendedDynamicRangeEnabled = true
|
||||
private var iosTargetColorspaceHintEnabled = true
|
||||
private var iosHdrComputePeakEnabled = true
|
||||
|
|
@ -195,6 +197,7 @@ object PlayerSettingsRepository {
|
|||
iosTargetPrimaries = IosTargetPrimaries.Auto
|
||||
iosTargetTransfer = IosTargetTransfer.Auto
|
||||
iosHardwareDecoderMode = IosHardwareDecoderMode.VideoToolbox
|
||||
iosAudioOutputMode = IosAudioOutputMode.Auto
|
||||
iosExtendedDynamicRangeEnabled = true
|
||||
iosTargetColorspaceHintEnabled = true
|
||||
iosHdrComputePeakEnabled = true
|
||||
|
|
@ -318,6 +321,9 @@ object PlayerSettingsRepository {
|
|||
iosHardwareDecoderMode = PlayerSettingsStorage.loadIosHardwareDecoderMode()
|
||||
?.let { runCatching { IosHardwareDecoderMode.valueOf(it) }.getOrNull() }
|
||||
?: IosHardwareDecoderMode.VideoToolbox
|
||||
iosAudioOutputMode = PlayerSettingsStorage.loadIosAudioOutputMode()
|
||||
?.let { runCatching { IosAudioOutputMode.valueOf(it) }.getOrNull() }
|
||||
?: IosAudioOutputMode.Auto
|
||||
iosExtendedDynamicRangeEnabled = PlayerSettingsStorage.loadIosExtendedDynamicRangeEnabled() ?: true
|
||||
iosTargetColorspaceHintEnabled = PlayerSettingsStorage.loadIosTargetColorspaceHintEnabled() ?: true
|
||||
iosHdrComputePeakEnabled = PlayerSettingsStorage.loadIosHdrComputePeakEnabled() ?: true
|
||||
|
|
@ -716,6 +722,13 @@ object PlayerSettingsRepository {
|
|||
PlayerSettingsStorage.saveIosHardwareDecoderMode(mode.name)
|
||||
}
|
||||
|
||||
fun setIosAudioOutputMode(mode: IosAudioOutputMode) {
|
||||
ensureLoaded()
|
||||
iosAudioOutputMode = mode
|
||||
publish()
|
||||
PlayerSettingsStorage.saveIosAudioOutputMode(mode.name)
|
||||
}
|
||||
|
||||
fun setIosExtendedDynamicRangeEnabled(enabled: Boolean) {
|
||||
ensureLoaded()
|
||||
iosVideoOutputPreset = IosVideoOutputPreset.Custom
|
||||
|
|
@ -853,6 +866,7 @@ object PlayerSettingsRepository {
|
|||
iosTargetPrimaries = iosTargetPrimaries,
|
||||
iosTargetTransfer = iosTargetTransfer,
|
||||
iosHardwareDecoderMode = iosHardwareDecoderMode,
|
||||
iosAudioOutputMode = iosAudioOutputMode,
|
||||
iosExtendedDynamicRangeEnabled = iosExtendedDynamicRangeEnabled,
|
||||
iosTargetColorspaceHintEnabled = iosTargetColorspaceHintEnabled,
|
||||
iosHdrComputePeakEnabled = iosHdrComputePeakEnabled,
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ internal expect object PlayerSettingsStorage {
|
|||
fun saveIosTargetTransfer(transfer: String)
|
||||
fun loadIosHardwareDecoderMode(): String?
|
||||
fun saveIosHardwareDecoderMode(mode: String)
|
||||
fun loadIosAudioOutputMode(): String?
|
||||
fun saveIosAudioOutputMode(mode: String)
|
||||
fun loadIosExtendedDynamicRangeEnabled(): Boolean?
|
||||
fun saveIosExtendedDynamicRangeEnabled(enabled: Boolean)
|
||||
fun loadIosTargetColorspaceHintEnabled(): Boolean?
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ import com.nuvio.app.features.player.AudioLanguageOption
|
|||
import com.nuvio.app.features.player.AvailableLanguageOptions
|
||||
import com.nuvio.app.features.player.ExternalPlayerApp
|
||||
import com.nuvio.app.features.player.ExternalPlayerPlatform
|
||||
import com.nuvio.app.features.player.IosAudioOutputMode
|
||||
import com.nuvio.app.features.player.IosHardwareDecoderMode
|
||||
import com.nuvio.app.features.player.localizedLabel
|
||||
import com.nuvio.app.features.player.IosTargetPrimaries
|
||||
|
|
@ -267,6 +268,7 @@ private fun PlaybackSettingsSection(
|
|||
var showReuseCacheDurationDialog by remember { mutableStateOf(false) }
|
||||
var showDecoderPriorityDialog by remember { mutableStateOf(false) }
|
||||
var showHoldToSpeedValueDialog by remember { mutableStateOf(false) }
|
||||
var showIosAudioOutputDialog by remember { mutableStateOf(false) }
|
||||
var showIosHardwareDecoderDialog by remember { mutableStateOf(false) }
|
||||
var showIosTargetPrimariesDialog by remember { mutableStateOf(false) }
|
||||
var showIosTargetTransferDialog by remember { mutableStateOf(false) }
|
||||
|
|
@ -782,6 +784,20 @@ private fun PlaybackSettingsSection(
|
|||
}
|
||||
|
||||
if (isIos) {
|
||||
SettingsSection(
|
||||
title = stringResource(Res.string.settings_playback_ios_audio_output_section),
|
||||
isTablet = isTablet,
|
||||
) {
|
||||
SettingsGroup(isTablet = isTablet) {
|
||||
SettingsNavigationRow(
|
||||
title = stringResource(Res.string.settings_playback_ios_audio_output),
|
||||
description = autoPlayPlayerSettings.iosAudioOutputMode.label,
|
||||
isTablet = isTablet,
|
||||
onClick = { showIosAudioOutputDialog = true },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SettingsSection(
|
||||
title = stringResource(Res.string.settings_playback_ios_video_output),
|
||||
isTablet = isTablet,
|
||||
|
|
@ -1263,6 +1279,27 @@ private fun PlaybackSettingsSection(
|
|||
)
|
||||
}
|
||||
|
||||
if (showIosAudioOutputDialog) {
|
||||
IosEnumSelectionDialog(
|
||||
title = stringResource(Res.string.settings_playback_ios_audio_output_dialog),
|
||||
options = IosAudioOutputMode.entries,
|
||||
selected = autoPlayPlayerSettings.iosAudioOutputMode,
|
||||
label = { it.label },
|
||||
description = {
|
||||
when (it) {
|
||||
IosAudioOutputMode.Auto -> stringResource(Res.string.settings_playback_ios_audio_output_auto_desc)
|
||||
IosAudioOutputMode.AvFoundation -> stringResource(Res.string.settings_playback_ios_audio_output_avfoundation_desc)
|
||||
IosAudioOutputMode.AudioUnit -> stringResource(Res.string.settings_playback_ios_audio_output_audiounit_desc)
|
||||
}
|
||||
},
|
||||
onSelect = {
|
||||
PlayerSettingsRepository.setIosAudioOutputMode(it)
|
||||
showIosAudioOutputDialog = false
|
||||
},
|
||||
onDismiss = { showIosAudioOutputDialog = false },
|
||||
)
|
||||
}
|
||||
|
||||
if (showIosTargetPrimariesDialog) {
|
||||
IosEnumSelectionDialog(
|
||||
title = stringResource(Res.string.settings_playback_ios_target_primaries_dialog),
|
||||
|
|
@ -1890,6 +1927,7 @@ private fun <T> IosEnumSelectionDialog(
|
|||
options: List<T>,
|
||||
selected: T,
|
||||
label: (T) -> String,
|
||||
description: @Composable (T) -> String? = { null },
|
||||
onSelect: (T) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
|
|
@ -1918,6 +1956,7 @@ private fun <T> IosEnumSelectionDialog(
|
|||
) {
|
||||
options.forEach { option ->
|
||||
val isSelected = option == selected
|
||||
val optionDescription = description(option)
|
||||
val containerColor = if (isSelected) {
|
||||
MaterialTheme.colorScheme.primary.copy(alpha = 0.14f)
|
||||
} else {
|
||||
|
|
@ -1937,12 +1976,23 @@ private fun <T> IosEnumSelectionDialog(
|
|||
.padding(horizontal = 14.dp, vertical = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = label(option),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
verticalArrangement = Arrangement.spacedBy(3.dp),
|
||||
) {
|
||||
Text(
|
||||
text = label(option),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
if (optionDescription != null) {
|
||||
Text(
|
||||
text = optionDescription,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier.size(24.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ interface NuvioPlayerBridge {
|
|||
saturation: Int,
|
||||
gamma: Int,
|
||||
)
|
||||
fun configureAudioOutput(audioOutput: String)
|
||||
fun setPlaybackSpeed(speed: Float)
|
||||
fun setMuted(muted: Boolean)
|
||||
fun setResizeMode(mode: Int) // 0=Fit, 1=Fill, 2=Zoom
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ actual fun PlatformPlayerSurface(
|
|||
}
|
||||
|
||||
private fun NuvioPlayerBridge.applyIosVideoOutputSettings(settings: PlayerSettingsUiState) {
|
||||
configureAudioOutput(audioOutput = settings.iosAudioOutputMode.mpvValue)
|
||||
configureVideoOutput(
|
||||
hardwareDecoder = settings.iosHardwareDecoderMode.mpvValue,
|
||||
targetColorspaceHint = settings.iosTargetColorspaceHintEnabled,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ actual object PlayerSettingsStorage {
|
|||
private const val iosTargetPrimariesKey = "ios_target_primaries"
|
||||
private const val iosTargetTransferKey = "ios_target_transfer"
|
||||
private const val iosHardwareDecoderModeKey = "ios_hardware_decoder_mode"
|
||||
private const val iosAudioOutputModeKey = "ios_audio_output_mode"
|
||||
private const val iosExtendedDynamicRangeEnabledKey = "ios_extended_dynamic_range_enabled"
|
||||
private const val iosTargetColorspaceHintEnabledKey = "ios_target_colorspace_hint_enabled"
|
||||
private const val iosHdrComputePeakEnabledKey = "ios_hdr_compute_peak_enabled"
|
||||
|
|
@ -127,6 +128,7 @@ actual object PlayerSettingsStorage {
|
|||
iosTargetPrimariesKey,
|
||||
iosTargetTransferKey,
|
||||
iosHardwareDecoderModeKey,
|
||||
iosAudioOutputModeKey,
|
||||
iosExtendedDynamicRangeEnabledKey,
|
||||
iosTargetColorspaceHintEnabledKey,
|
||||
iosHdrComputePeakEnabledKey,
|
||||
|
|
@ -735,6 +737,13 @@ actual object PlayerSettingsStorage {
|
|||
NSUserDefaults.standardUserDefaults.setObject(mode, forKey = ProfileScopedKey.of(iosHardwareDecoderModeKey))
|
||||
}
|
||||
|
||||
actual fun loadIosAudioOutputMode(): String? =
|
||||
NSUserDefaults.standardUserDefaults.stringForKey(ProfileScopedKey.of(iosAudioOutputModeKey))
|
||||
|
||||
actual fun saveIosAudioOutputMode(mode: String) {
|
||||
NSUserDefaults.standardUserDefaults.setObject(mode, forKey = ProfileScopedKey.of(iosAudioOutputModeKey))
|
||||
}
|
||||
|
||||
actual fun loadIosExtendedDynamicRangeEnabled(): Boolean? =
|
||||
loadBoolean(iosExtendedDynamicRangeEnabledKey)
|
||||
|
||||
|
|
@ -844,6 +853,7 @@ actual object PlayerSettingsStorage {
|
|||
loadIosTargetPrimaries()?.let { put(iosTargetPrimariesKey, encodeSyncString(it)) }
|
||||
loadIosTargetTransfer()?.let { put(iosTargetTransferKey, encodeSyncString(it)) }
|
||||
loadIosHardwareDecoderMode()?.let { put(iosHardwareDecoderModeKey, encodeSyncString(it)) }
|
||||
loadIosAudioOutputMode()?.let { put(iosAudioOutputModeKey, encodeSyncString(it)) }
|
||||
loadIosExtendedDynamicRangeEnabled()?.let { put(iosExtendedDynamicRangeEnabledKey, encodeSyncBoolean(it)) }
|
||||
loadIosTargetColorspaceHintEnabled()?.let { put(iosTargetColorspaceHintEnabledKey, encodeSyncBoolean(it)) }
|
||||
loadIosHdrComputePeakEnabled()?.let { put(iosHdrComputePeakEnabledKey, encodeSyncBoolean(it)) }
|
||||
|
|
@ -910,6 +920,7 @@ actual object PlayerSettingsStorage {
|
|||
payload.decodeSyncString(iosTargetPrimariesKey)?.let(::saveIosTargetPrimaries)
|
||||
payload.decodeSyncString(iosTargetTransferKey)?.let(::saveIosTargetTransfer)
|
||||
payload.decodeSyncString(iosHardwareDecoderModeKey)?.let(::saveIosHardwareDecoderMode)
|
||||
payload.decodeSyncString(iosAudioOutputModeKey)?.let(::saveIosAudioOutputMode)
|
||||
payload.decodeSyncBoolean(iosExtendedDynamicRangeEnabledKey)?.let(::saveIosExtendedDynamicRangeEnabled)
|
||||
payload.decodeSyncBoolean(iosTargetColorspaceHintEnabledKey)?.let(::saveIosTargetColorspaceHintEnabled)
|
||||
payload.decodeSyncBoolean(iosHdrComputePeakEnabledKey)?.let(::saveIosHdrComputePeakEnabled)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ final class MPVPlayerBridgeImpl: NSObject, NuvioPlayerBridge {
|
|||
gamma: Int(gamma)
|
||||
)
|
||||
}
|
||||
func configureAudioOutput(audioOutput: String) {
|
||||
playerVC?.configureAudioOutput(audioOutput: audioOutput)
|
||||
}
|
||||
func setPlaybackSpeed(speed: Float) { playerVC?.setSpeed(speed) }
|
||||
func setMuted(muted: Bool) { playerVC?.setMuted(muted) }
|
||||
func setResizeMode(mode: Int32) { playerVC?.setResize(Int(mode)) }
|
||||
|
|
@ -192,6 +195,8 @@ private struct PendingLoadRequest {
|
|||
|
||||
final class MPVPlayerViewController: UIViewController {
|
||||
|
||||
private static let defaultAudioOutput = "avfoundation,audiounit,"
|
||||
|
||||
private let errorStateLock = NSLock()
|
||||
private var metalLayer = MetalLayer()
|
||||
private var lastAppliedDrawableSize: CGSize = .zero
|
||||
|
|
@ -318,7 +323,8 @@ final class MPVPlayerViewController: UIViewController {
|
|||
checkError(mpv_set_option_string(mpv, "gpu-api", "vulkan"))
|
||||
checkError(mpv_set_option_string(mpv, "gpu-context", "moltenvk"))
|
||||
checkError(mpv_set_option_string(mpv, "hwdec", "videotoolbox"))
|
||||
checkError(mpv_set_option_string(mpv, "audio-channels", "stereo"))
|
||||
checkError(mpv_set_option_string(mpv, "ao", Self.defaultAudioOutput))
|
||||
checkError(mpv_set_option_string(mpv, "audio-channels", "auto"))
|
||||
checkError(mpv_set_option_string(mpv, "audio-fallback-to-null", "yes"))
|
||||
checkError(mpv_set_option_string(mpv, "vulkan-swap-mode", "fifo"))
|
||||
checkError(mpv_set_option_string(mpv, "vulkan-queue-count", "1"))
|
||||
|
|
@ -512,6 +518,11 @@ final class MPVPlayerViewController: UIViewController {
|
|||
setVideoEqualizer("gamma", gamma)
|
||||
}
|
||||
|
||||
func configureAudioOutput(audioOutput: String) {
|
||||
guard mpv != nil else { return }
|
||||
setStringProperty("ao", audioOutput)
|
||||
}
|
||||
|
||||
func setSpeed(_ speed: Float) {
|
||||
guard mpv != nil else { return }
|
||||
var s = Double(speed)
|
||||
|
|
@ -853,6 +864,7 @@ final class MPVPlayerViewController: UIViewController {
|
|||
self.clearPlaybackError()
|
||||
self.isPlayerLoading = false
|
||||
self.updateState()
|
||||
self.logCurrentAudioOutput()
|
||||
}
|
||||
case MPV_EVENT_END_FILE:
|
||||
if let data = eventPtr.pointee.data {
|
||||
|
|
@ -943,6 +955,19 @@ final class MPVPlayerViewController: UIViewController {
|
|||
return Int(data)
|
||||
}
|
||||
|
||||
private func logCurrentAudioOutput() {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||
guard let self, self.mpv != nil else { return }
|
||||
let currentAo = self.getString("current-ao") ?? "unknown"
|
||||
let channels = self.getString("audio-out-params/hr-channels")
|
||||
?? self.getString("audio-params/hr-channels")
|
||||
?? "unknown"
|
||||
let channelCount = self.getInt("audio-out-params/channel-count")
|
||||
let codec = self.getString("audio-codec-name") ?? "unknown"
|
||||
print("[MPV] Audio output: ao=\(currentAo), channels=\(channels), channelCount=\(channelCount), codec=\(codec)")
|
||||
}
|
||||
}
|
||||
|
||||
private func checkError(_ status: CInt) {
|
||||
if status < 0 {
|
||||
print("[MPV] API error: \(String(cString: mpv_error_string(status)))")
|
||||
|
|
|
|||
Loading…
Reference in a new issue