Compare commits
1 Commits
android-55
...
android-53
Author | SHA1 | Date | |
---|---|---|---|
2f444a9fd5 |
@ -524,7 +524,7 @@ if (ENABLE_SDL2)
|
|||||||
if (YUZU_USE_BUNDLED_SDL2)
|
if (YUZU_USE_BUNDLED_SDL2)
|
||||||
# Detect toolchain and platform
|
# Detect toolchain and platform
|
||||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
||||||
set(SDL2_VER "SDL2-2.28.2")
|
set(SDL2_VER "SDL2-2.28.1")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
||||||
endif()
|
endif()
|
||||||
|
2
externals/SDL
vendored
2
externals/SDL
vendored
Submodule externals/SDL updated: 031912c4b6...116a5344ff
4
externals/ffmpeg/CMakeLists.txt
vendored
4
externals/ffmpeg/CMakeLists.txt
vendored
@ -164,7 +164,7 @@ if (NOT WIN32 AND NOT ANDROID)
|
|||||||
--enable-decoder=h264
|
--enable-decoder=h264
|
||||||
--enable-decoder=vp8
|
--enable-decoder=vp8
|
||||||
--enable-decoder=vp9
|
--enable-decoder=vp9
|
||||||
--enable-filter=yadif,scale
|
--enable-filter=yadif
|
||||||
--cc="${FFmpeg_CC}"
|
--cc="${FFmpeg_CC}"
|
||||||
--cxx="${FFmpeg_CXX}"
|
--cxx="${FFmpeg_CXX}"
|
||||||
${FFmpeg_HWACCEL_FLAGS}
|
${FFmpeg_HWACCEL_FLAGS}
|
||||||
@ -254,7 +254,7 @@ elseif(ANDROID)
|
|||||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
|
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
# Use yuzu FFmpeg binaries
|
# Use yuzu FFmpeg binaries
|
||||||
set(FFmpeg_EXT_NAME "ffmpeg-6.0")
|
set(FFmpeg_EXT_NAME "ffmpeg-5.1.3")
|
||||||
set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
|
set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
|
||||||
download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
|
download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
|
||||||
set(FFmpeg_FOUND YES)
|
set(FFmpeg_FOUND YES)
|
||||||
|
@ -56,6 +56,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
android:name="org.yuzu.yuzu_emu.activities.EmulationActivity"
|
android:name="org.yuzu.yuzu_emu.activities.EmulationActivity"
|
||||||
android:theme="@style/Theme.Yuzu.Main"
|
android:theme="@style/Theme.Yuzu.Main"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
|
android:screenOrientation="userLandscape"
|
||||||
android:supportsPictureInPicture="true"
|
android:supportsPictureInPicture="true"
|
||||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode"
|
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
@ -66,14 +67,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
<data android:mimeType="application/octet-stream" />
|
<data android:mimeType="application/octet-stream" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<data
|
|
||||||
android:mimeType="application/octet-stream"
|
|
||||||
android:scheme="content"/>
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.nfc.action.TECH_DISCOVERED"
|
android:name="android.nfc.action.TECH_DISCOVERED"
|
||||||
android:resource="@xml/nfc_tech_filter" />
|
android:resource="@xml/nfc_tech_filter" />
|
||||||
|
@ -11,6 +11,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
@ -245,5 +246,17 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
|
|||||||
settings.putExtra(ARG_GAME_ID, gameId)
|
settings.putExtra(ARG_GAME_ID, gameId)
|
||||||
context.startActivity(settings)
|
context.startActivity(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun launch(
|
||||||
|
context: Context,
|
||||||
|
launcher: ActivityResultLauncher<Intent>,
|
||||||
|
menuTag: String?,
|
||||||
|
gameId: String?
|
||||||
|
) {
|
||||||
|
val settings = Intent(context, SettingsActivity::class.java)
|
||||||
|
settings.putExtra(ARG_MENU_TAG, menuTag)
|
||||||
|
settings.putExtra(ARG_GAME_ID, gameId)
|
||||||
|
launcher.launch(settings)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,11 @@ import android.annotation.SuppressLint
|
|||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
@ -19,6 +19,8 @@ import android.util.Rational
|
|||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
@ -48,7 +50,6 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
|
||||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
|
||||||
import org.yuzu.yuzu_emu.overlay.InputOverlay
|
import org.yuzu.yuzu_emu.overlay.InputOverlay
|
||||||
import org.yuzu.yuzu_emu.utils.*
|
import org.yuzu.yuzu_emu.utils.*
|
||||||
|
|
||||||
@ -61,12 +62,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
private var _binding: FragmentEmulationBinding? = null
|
private var _binding: FragmentEmulationBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private val args by navArgs<EmulationFragmentArgs>()
|
val args by navArgs<EmulationFragmentArgs>()
|
||||||
|
|
||||||
private lateinit var game: Game
|
|
||||||
|
|
||||||
private var isInFoldableLayout = false
|
private var isInFoldableLayout = false
|
||||||
|
|
||||||
|
private lateinit var onReturnFromSettings: ActivityResultLauncher<Intent>
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
if (context is EmulationActivity) {
|
if (context is EmulationActivity) {
|
||||||
@ -80,6 +81,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
.collect { updateFoldableLayout(context, it) }
|
.collect { updateFoldableLayout(context, it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onReturnFromSettings = context.activityResultRegistry.register(
|
||||||
|
"SettingsResult",
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { updateScreenLayout() }
|
||||||
} else {
|
} else {
|
||||||
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
|
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
|
||||||
}
|
}
|
||||||
@ -91,25 +97,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val intentUri: Uri? = requireActivity().intent.data
|
|
||||||
var intentGame: Game? = null
|
|
||||||
if (intentUri != null) {
|
|
||||||
intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri))) {
|
|
||||||
GameHelper.getGame(requireActivity().intent.data!!, false)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
game = if (args.game != null) {
|
|
||||||
args.game!!
|
|
||||||
} else {
|
|
||||||
intentGame ?: error("[EmulationFragment] No bootable game present!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||||
retainInstance = true
|
retainInstance = true
|
||||||
preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||||
emulationState = EmulationState(game.path)
|
emulationState = EmulationState(args.game.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,7 +124,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
updateShowFpsOverlay()
|
updateShowFpsOverlay()
|
||||||
|
|
||||||
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
|
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
|
||||||
game.title
|
args.game.title
|
||||||
binding.inGameMenu.setNavigationItemSelectedListener {
|
binding.inGameMenu.setNavigationItemSelectedListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.menu_pause_emulation -> {
|
R.id.menu_pause_emulation -> {
|
||||||
@ -158,7 +149,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_settings -> {
|
R.id.menu_settings -> {
|
||||||
SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "")
|
SettingsActivity.launch(
|
||||||
|
requireContext(),
|
||||||
|
onReturnFromSettings,
|
||||||
|
SettingsFile.FILE_NAME_CONFIG,
|
||||||
|
""
|
||||||
|
)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,13 +63,13 @@ object GameHelper {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (Game.extensions.contains(FileUtil.getExtension(it.uri))) {
|
if (Game.extensions.contains(FileUtil.getExtension(it.uri))) {
|
||||||
games.add(getGame(it.uri, true))
|
games.add(getGame(it.uri))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGame(uri: Uri, addedToLibrary: Boolean): Game {
|
private fun getGame(uri: Uri): Game {
|
||||||
val filePath = uri.toString()
|
val filePath = uri.toString()
|
||||||
var name = NativeLibrary.getTitle(filePath)
|
var name = NativeLibrary.getTitle(filePath)
|
||||||
|
|
||||||
@ -94,14 +94,12 @@ object GameHelper {
|
|||||||
NativeLibrary.isHomebrew(filePath)
|
NativeLibrary.isHomebrew(filePath)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (addedToLibrary) {
|
|
||||||
val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L)
|
val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L)
|
||||||
if (addedTime == 0L) {
|
if (addedTime == 0L) {
|
||||||
preferences.edit()
|
preferences.edit()
|
||||||
.putLong(newGame.keyAddedToLibraryTime, System.currentTimeMillis())
|
.putLong(newGame.keyAddedToLibraryTime, System.currentTimeMillis())
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return newGame
|
return newGame
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import android.content.Context
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.Rational
|
import android.util.Rational
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class FixedRatioSurfaceView @JvmOverloads constructor(
|
class FixedRatioSurfaceView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
@ -21,44 +22,27 @@ class FixedRatioSurfaceView @JvmOverloads constructor(
|
|||||||
*/
|
*/
|
||||||
fun setAspectRatio(ratio: Rational?) {
|
fun setAspectRatio(ratio: Rational?) {
|
||||||
aspectRatio = ratio?.toFloat() ?: 0f
|
aspectRatio = ratio?.toFloat() ?: 0f
|
||||||
requestLayout()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
val displayWidth: Float = MeasureSpec.getSize(widthMeasureSpec).toFloat()
|
|
||||||
val displayHeight: Float = MeasureSpec.getSize(heightMeasureSpec).toFloat()
|
|
||||||
if (aspectRatio != 0f) {
|
|
||||||
val displayAspect = displayWidth / displayHeight
|
|
||||||
if (displayAspect < aspectRatio) {
|
|
||||||
// Max out width
|
|
||||||
val halfHeight = displayHeight / 2
|
|
||||||
val surfaceHeight = displayWidth / aspectRatio
|
|
||||||
val newTop: Float = halfHeight - (surfaceHeight / 2)
|
|
||||||
val newBottom: Float = halfHeight + (surfaceHeight / 2)
|
|
||||||
super.onMeasure(
|
|
||||||
widthMeasureSpec,
|
|
||||||
MeasureSpec.makeMeasureSpec(
|
|
||||||
newBottom.toInt() - newTop.toInt(),
|
|
||||||
MeasureSpec.EXACTLY
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
// Max out height
|
|
||||||
val halfWidth = displayWidth / 2
|
|
||||||
val surfaceWidth = displayHeight * aspectRatio
|
|
||||||
val newLeft: Float = halfWidth - (surfaceWidth / 2)
|
|
||||||
val newRight: Float = halfWidth + (surfaceWidth / 2)
|
|
||||||
super.onMeasure(
|
|
||||||
MeasureSpec.makeMeasureSpec(
|
|
||||||
newRight.toInt() - newLeft.toInt(),
|
|
||||||
MeasureSpec.EXACTLY
|
|
||||||
),
|
|
||||||
heightMeasureSpec
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||||
|
val width = MeasureSpec.getSize(widthMeasureSpec)
|
||||||
|
val height = MeasureSpec.getSize(heightMeasureSpec)
|
||||||
|
if (aspectRatio != 0f) {
|
||||||
|
val newWidth: Int
|
||||||
|
val newHeight: Int
|
||||||
|
if (height * aspectRatio < width) {
|
||||||
|
newWidth = (height * aspectRatio).roundToInt()
|
||||||
|
newHeight = height
|
||||||
|
} else {
|
||||||
|
newWidth = width
|
||||||
|
newHeight = (width / aspectRatio).roundToInt()
|
||||||
|
}
|
||||||
|
val left = (width - newWidth) / 2
|
||||||
|
val top = (height - newHeight) / 2
|
||||||
|
setLeftTopRightBottom(left, top, left + newWidth, top + newHeight)
|
||||||
|
} else {
|
||||||
|
setLeftTopRightBottom(0, 0, width, height)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,7 @@
|
|||||||
tools:layout="@layout/fragment_emulation" >
|
tools:layout="@layout/fragment_emulation" >
|
||||||
<argument
|
<argument
|
||||||
android:name="game"
|
android:name="game"
|
||||||
app:argType="org.yuzu.yuzu_emu.model.Game"
|
app:argType="org.yuzu.yuzu_emu.model.Game" />
|
||||||
app:nullable="true"
|
|
||||||
android:defaultValue="@null" />
|
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
</navigation>
|
</navigation>
|
||||||
|
@ -62,9 +62,7 @@
|
|||||||
android:label="EmulationActivity">
|
android:label="EmulationActivity">
|
||||||
<argument
|
<argument
|
||||||
android:name="game"
|
android:name="game"
|
||||||
app:argType="org.yuzu.yuzu_emu.model.Game"
|
app:argType="org.yuzu.yuzu_emu.model.Game" />
|
||||||
app:nullable="true"
|
|
||||||
android:defaultValue="@null" />
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<action
|
<action
|
||||||
|
@ -778,7 +778,7 @@ u32 System::DropVoices(CommandBuffer& command_buffer, u32 estimated_process_time
|
|||||||
while (i < command_buffer.count) {
|
while (i < command_buffer.count) {
|
||||||
const auto node_id{cmd->node_id};
|
const auto node_id{cmd->node_id};
|
||||||
const auto node_id_type{cmd->node_id >> 28};
|
const auto node_id_type{cmd->node_id >> 28};
|
||||||
const auto node_id_base{(cmd->node_id >> 16) & 0xFFF};
|
const auto node_id_base{cmd->node_id & 0xFFF};
|
||||||
|
|
||||||
// If the new estimated process time falls below the limit, we're done dropping.
|
// If the new estimated process time falls below the limit, we're done dropping.
|
||||||
if (estimated_process_time <= time_limit) {
|
if (estimated_process_time <= time_limit) {
|
||||||
|
@ -364,7 +364,7 @@ bool IsCubebSuitable() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get min latency
|
// Test min latency
|
||||||
cubeb_stream_params params{};
|
cubeb_stream_params params{};
|
||||||
params.rate = TargetSampleRate;
|
params.rate = TargetSampleRate;
|
||||||
params.channels = 2;
|
params.channels = 2;
|
||||||
@ -380,6 +380,11 @@ bool IsCubebSuitable() {
|
|||||||
}
|
}
|
||||||
latency = std::max(latency, TargetSampleCount * 2);
|
latency = std::max(latency, TargetSampleCount * 2);
|
||||||
|
|
||||||
|
if (latency > TargetSampleCount * 3) {
|
||||||
|
LOG_ERROR(Audio_Sink, "Cubeb latency is too high, it is not suitable.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Test opening a device with standard parameters
|
// Test opening a device with standard parameters
|
||||||
cubeb_devid output_device{0};
|
cubeb_devid output_device{0};
|
||||||
cubeb_devid input_device{0};
|
cubeb_devid input_device{0};
|
||||||
|
@ -83,7 +83,7 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_INFO(Service_Audio, "Auto-selecting the {} backend",
|
LOG_ERROR(Service_Audio, "Auto-selecting the {} backend",
|
||||||
Settings::CanonicalizeEnum(iter->id));
|
Settings::CanonicalizeEnum(iter->id));
|
||||||
} else {
|
} else {
|
||||||
if (iter != std::end(sink_details) && !iter->is_suitable()) {
|
if (iter != std::end(sink_details) && !iter->is_suitable()) {
|
||||||
|
@ -174,7 +174,7 @@ public:
|
|||||||
{6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"},
|
{6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"},
|
||||||
{7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
|
{7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
|
||||||
{8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
|
{8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
|
||||||
{9, &IHardwareOpusDecoderManager::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"},
|
{9, nullptr, "DecodeInterleavedForMultiStream"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@ -206,16 +206,6 @@ private:
|
|||||||
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior);
|
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecodeInterleavedForMultiStream(HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Audio, "called");
|
|
||||||
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto extra_behavior = rp.Pop<bool>() ? OpusDecoderState::ExtraBehavior::ResetContext
|
|
||||||
: OpusDecoderState::ExtraBehavior::None;
|
|
||||||
|
|
||||||
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior);
|
|
||||||
}
|
|
||||||
|
|
||||||
OpusDecoderState decoder_state;
|
OpusDecoderState decoder_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -364,40 +354,6 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
|
|||||||
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
|
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
|
|
||||||
OpusMultiStreamParametersEx params;
|
|
||||||
std::memcpy(¶ms, ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
|
|
||||||
|
|
||||||
const auto& sample_rate = params.sample_rate;
|
|
||||||
const auto& channel_count = params.channel_count;
|
|
||||||
|
|
||||||
LOG_INFO(
|
|
||||||
Audio,
|
|
||||||
"called with sample_rate={}, channel_count={}, number_streams={}, number_stereo_streams={}",
|
|
||||||
sample_rate, channel_count, params.number_streams, params.number_stereo_streams);
|
|
||||||
|
|
||||||
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
|
|
||||||
sample_rate == 12000 || sample_rate == 8000,
|
|
||||||
"Invalid sample rate");
|
|
||||||
|
|
||||||
int error = 0;
|
|
||||||
OpusDecoderPtr decoder{opus_multistream_decoder_create(
|
|
||||||
sample_rate, static_cast<int>(channel_count), params.number_streams,
|
|
||||||
params.number_stereo_streams, params.channel_mappings.data(), &error)};
|
|
||||||
if (error != OPUS_OK || decoder == nullptr) {
|
|
||||||
LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
// TODO(ogniK): Use correct error code
|
|
||||||
rb.Push(ResultUnknown);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushIpcInterface<IHardwareOpusDecoderManager>(
|
|
||||||
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
|
|
||||||
}
|
|
||||||
|
|
||||||
HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
|
HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
|
{0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
|
||||||
@ -406,8 +362,7 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
|
|||||||
{3, nullptr, "GetWorkBufferSizeForMultiStream"},
|
{3, nullptr, "GetWorkBufferSizeForMultiStream"},
|
||||||
{4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
|
{4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
|
||||||
{5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
|
{5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
|
||||||
{6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx,
|
{6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
|
||||||
"OpenHardwareOpusDecoderForMultiStreamEx"},
|
|
||||||
{7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
|
{7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
|
||||||
{8, nullptr, "GetWorkBufferSizeExEx"},
|
{8, nullptr, "GetWorkBufferSizeExEx"},
|
||||||
{9, nullptr, "GetWorkBufferSizeForMultiStreamExEx"},
|
{9, nullptr, "GetWorkBufferSizeForMultiStreamExEx"},
|
||||||
|
@ -18,10 +18,8 @@ struct OpusMultiStreamParametersEx {
|
|||||||
u32 number_stereo_streams;
|
u32 number_stereo_streams;
|
||||||
u32 use_large_frame_size;
|
u32 use_large_frame_size;
|
||||||
u32 padding;
|
u32 padding;
|
||||||
std::array<u8, 0x100> channel_mappings;
|
std::array<u32, 64> channel_mappings;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,
|
|
||||||
"OpusMultiStreamParametersEx has incorrect size");
|
|
||||||
|
|
||||||
class HwOpus final : public ServiceFramework<HwOpus> {
|
class HwOpus final : public ServiceFramework<HwOpus> {
|
||||||
public:
|
public:
|
||||||
@ -31,7 +29,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
void OpenHardwareOpusDecoder(HLERequestContext& ctx);
|
void OpenHardwareOpusDecoder(HLERequestContext& ctx);
|
||||||
void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
|
void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
|
||||||
void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx);
|
|
||||||
void GetWorkBufferSize(HLERequestContext& ctx);
|
void GetWorkBufferSize(HLERequestContext& ctx);
|
||||||
void GetWorkBufferSizeEx(HLERequestContext& ctx);
|
void GetWorkBufferSizeEx(HLERequestContext& ctx);
|
||||||
void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
|
void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
|
||||||
|
@ -19,12 +19,6 @@ enum class ServerEnvironmentType : u8 {
|
|||||||
Dp,
|
Dp,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is nn::nsd::EnvironmentIdentifier
|
|
||||||
struct EnvironmentIdentifier {
|
|
||||||
std::array<u8, 8> identifier;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(EnvironmentIdentifier) == 0x8);
|
|
||||||
|
|
||||||
NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
|
NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
@ -107,9 +101,8 @@ void NSD::ResolveEx(HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NSD::GetEnvironmentIdentifier(HLERequestContext& ctx) {
|
void NSD::GetEnvironmentIdentifier(HLERequestContext& ctx) {
|
||||||
constexpr EnvironmentIdentifier lp1 = {
|
const std::string environment_identifier = "lp1";
|
||||||
.identifier = {'l', 'p', '1', '\0', '\0', '\0', '\0', '\0'}};
|
ctx.WriteBuffer(environment_identifier);
|
||||||
ctx.WriteBuffer(lp1);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -150,12 +150,6 @@ static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestConte
|
|||||||
const std::string host = Common::StringFromBuffer(host_buffer);
|
const std::string host = Common::StringFromBuffer(host_buffer);
|
||||||
// For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions.
|
// For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions.
|
||||||
|
|
||||||
// Prevent resolution of Nintendo servers
|
|
||||||
if (host.find("srv.nintendo.net") != std::string::npos) {
|
|
||||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
|
||||||
return {0, GetAddrInfoError::AGAIN};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = Network::GetAddressInfo(host, /*service*/ std::nullopt);
|
auto res = Network::GetAddressInfo(host, /*service*/ std::nullopt);
|
||||||
if (!res.has_value()) {
|
if (!res.has_value()) {
|
||||||
return {0, Translate(res.error())};
|
return {0, Translate(res.error())};
|
||||||
@ -267,12 +261,6 @@ static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext
|
|||||||
const auto host_buffer = ctx.ReadBuffer(0);
|
const auto host_buffer = ctx.ReadBuffer(0);
|
||||||
const std::string host = Common::StringFromBuffer(host_buffer);
|
const std::string host = Common::StringFromBuffer(host_buffer);
|
||||||
|
|
||||||
// Prevent resolution of Nintendo servers
|
|
||||||
if (host.find("srv.nintendo.net") != std::string::npos) {
|
|
||||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
|
||||||
return {0, GetAddrInfoError::AGAIN};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::string> service = std::nullopt;
|
std::optional<std::string> service = std::nullopt;
|
||||||
if (ctx.CanReadBuffer(1)) {
|
if (ctx.CanReadBuffer(1)) {
|
||||||
const std::span<const u8> service_buffer = ctx.ReadBuffer(1);
|
const std::span<const u8> service_buffer = ctx.ReadBuffer(1);
|
||||||
|
@ -319,7 +319,6 @@ void Codec::Decode() {
|
|||||||
LOG_WARNING(Service_NVDRV, "Zero width or height in frame");
|
LOG_WARNING(Service_NVDRV, "Zero width or height in frame");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool is_interlaced = initial_frame->interlaced_frame != 0;
|
|
||||||
if (av_codec_ctx->hw_device_ctx) {
|
if (av_codec_ctx->hw_device_ctx) {
|
||||||
final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
|
final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
|
||||||
ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed");
|
ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed");
|
||||||
@ -335,7 +334,7 @@ void Codec::Decode() {
|
|||||||
UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
|
UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!is_interlaced) {
|
if (!final_frame->interlaced_frame) {
|
||||||
av_frames.push(std::move(final_frame));
|
av_frames.push(std::move(final_frame));
|
||||||
} else {
|
} else {
|
||||||
if (!filters_initialized) {
|
if (!filters_initialized) {
|
||||||
|
Reference in New Issue
Block a user