Compare commits

..

1 Commits

Author SHA1 Message Date
Tygyh
4654686a26
Merge 7b496b2f5b into 1786e34bd3 2025-06-07 18:40:01 -05:00
14 changed files with 93 additions and 192 deletions

View File

@ -1,28 +0,0 @@
package org.dolphinemu.dolphinemu.utils
import android.content.Context
import android.media.AudioManager
import androidx.annotation.Keep
import org.dolphinemu.dolphinemu.DolphinApplication
object AudioUtils {
@JvmStatic @Keep
fun getSampleRate(): Int =
getAudioServiceProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE, 48000)
@JvmStatic @Keep
fun getFramesPerBuffer(): Int =
getAudioServiceProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER, 256)
private fun getAudioServiceProperty(property: String, fallback: Int): Int {
return try {
val context = DolphinApplication.getAppContext()
val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
Integer.parseUnsignedInt(am.getProperty(property))
} catch (e: NullPointerException) {
fallback
} catch (e: NumberFormatException) {
fallback
}
}
}

View File

@ -122,10 +122,6 @@ static jmethodID s_permission_handler_request_record_audio_permission;
static jmethodID s_runnable_run; static jmethodID s_runnable_run;
static jclass s_audio_utils_class;
static jmethodID s_audio_utils_get_sample_rate;
static jmethodID s_audio_utils_get_frames_per_buffer;
namespace IDCache namespace IDCache
{ {
JNIEnv* GetEnvForThread() JNIEnv* GetEnvForThread()
@ -566,21 +562,6 @@ jmethodID GetRunnableRun()
return s_runnable_run; return s_runnable_run;
} }
jclass GetAudioUtilsClass()
{
return s_audio_utils_class;
}
jmethodID GetAudioUtilsGetSampleRate()
{
return s_audio_utils_get_sample_rate;
}
jmethodID GetAudioUtilsGetFramesPerBuffer()
{
return s_audio_utils_get_frames_per_buffer;
}
} // namespace IDCache } // namespace IDCache
extern "C" { extern "C" {
@ -817,13 +798,6 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
s_runnable_run = env->GetMethodID(runnable_class, "run", "()V"); s_runnable_run = env->GetMethodID(runnable_class, "run", "()V");
env->DeleteLocalRef(runnable_class); env->DeleteLocalRef(runnable_class);
const jclass audio_utils_class = env->FindClass("org/dolphinemu/dolphinemu/utils/AudioUtils");
s_audio_utils_class = reinterpret_cast<jclass>(env->NewGlobalRef(audio_utils_class));
s_audio_utils_get_sample_rate = env->GetStaticMethodID(audio_utils_class, "getSampleRate", "()I");
s_audio_utils_get_frames_per_buffer =
env->GetStaticMethodID(audio_utils_class, "getFramesPerBuffer", "()I");
env->DeleteLocalRef(audio_utils_class);
return JNI_VERSION; return JNI_VERSION;
} }
@ -860,6 +834,5 @@ JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
env->DeleteGlobalRef(s_core_device_control_class); env->DeleteGlobalRef(s_core_device_control_class);
env->DeleteGlobalRef(s_input_detector_class); env->DeleteGlobalRef(s_input_detector_class);
env->DeleteGlobalRef(s_permission_handler_class); env->DeleteGlobalRef(s_permission_handler_class);
env->DeleteGlobalRef(s_audio_utils_class);
} }
} }

View File

@ -121,8 +121,4 @@ jmethodID GetPermissionHandlerRequestRecordAudioPermission();
jmethodID GetRunnableRun(); jmethodID GetRunnableRun();
jclass GetAudioUtilsClass();
jmethodID GetAudioUtilsGetSampleRate();
jmethodID GetAudioUtilsGetFramesPerBuffer();
} // namespace IDCache } // namespace IDCache

View File

@ -16,7 +16,6 @@
#include "AudioCommon/WASAPIStream.h" #include "AudioCommon/WASAPIStream.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/TimeUtil.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/System.h" #include "Core/System.h"
@ -220,11 +219,8 @@ void StartAudioDump(Core::System& system)
std::string path_prefix = File::GetUserPath(D_DUMPAUDIO_IDX) + SConfig::GetInstance().GetGameID(); std::string path_prefix = File::GetUserPath(D_DUMPAUDIO_IDX) + SConfig::GetInstance().GetGameID();
const auto local_time = Common::LocalTime(start_time); std::string base_name =
if (!local_time) fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, fmt::localtime(start_time));
return;
std::string base_name = fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, *local_time);
const std::string audio_file_name_dtk = fmt::format("{}_dtkdump.wav", base_name); const std::string audio_file_name_dtk = fmt::format("{}_dtkdump.wav", base_name);
const std::string audio_file_name_dsp = fmt::format("{}_dspdump.wav", base_name); const std::string audio_file_name_dsp = fmt::format("{}_dspdump.wav", base_name);

View File

@ -8,27 +8,40 @@
#include <SLES/OpenSLES.h> #include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h> #include <SLES/OpenSLES_Android.h>
#include <jni.h>
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "jni/AndroidCommon/IDCache.h"
void OpenSLESStream::BQPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context) // engine interfaces
{ static SLObjectItf engineObject;
reinterpret_cast<OpenSLESStream*>(context)->PushSamples(bq); static SLEngineItf engineEngine;
} static SLObjectItf outputMixObject;
void OpenSLESStream::PushSamples(SLAndroidSimpleBufferQueueItf bq) // buffer queue player interfaces
static SLObjectItf bqPlayerObject = nullptr;
static SLPlayItf bqPlayerPlay;
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
static SLVolumeItf bqPlayerVolume;
static Mixer* g_mixer;
#define BUFFER_SIZE 512
#define BUFFER_SIZE_IN_SAMPLES (BUFFER_SIZE / 2)
// Double buffering.
static short buffer[2][BUFFER_SIZE];
static int curBuffer = 0;
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
{ {
ASSERT(bq == m_bq_player_buffer_queue); ASSERT(bq == bqPlayerBufferQueue);
ASSERT(nullptr == context);
// Render to the fresh buffer // Render to the fresh buffer
m_mixer->Mix(m_buffer[m_current_buffer].data(), m_frames_per_buffer); g_mixer->Mix(reinterpret_cast<short*>(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES);
SLresult result = (*bq)->Enqueue(bq, m_buffer[m_current_buffer].data(), m_bytes_per_buffer); SLresult result =
m_current_buffer ^= 1; // Switch buffer (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[0]));
curBuffer ^= 1; // Switch buffer
// Comment from sample code: // Comment from sample code:
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
@ -38,78 +51,61 @@ void OpenSLESStream::PushSamples(SLAndroidSimpleBufferQueueItf bq)
bool OpenSLESStream::Init() bool OpenSLESStream::Init()
{ {
JNIEnv* env = IDCache::GetEnvForThread();
jclass audio_utils = IDCache::GetAudioUtilsClass();
const SLuint32 sample_rate =
env->CallStaticIntMethod(audio_utils, IDCache::GetAudioUtilsGetSampleRate());
m_frames_per_buffer =
env->CallStaticIntMethod(audio_utils, IDCache::GetAudioUtilsGetFramesPerBuffer());
INFO_LOG_FMT(AUDIO, "OpenSLES configuration: {} Hz, {} frames per buffer", sample_rate,
m_frames_per_buffer);
constexpr SLuint32 channels = 2;
const SLuint32 samples_per_buffer = m_frames_per_buffer * channels;
m_bytes_per_buffer = m_frames_per_buffer * channels * sizeof(m_buffer[0][0]);
for (std::vector<short>& buffer : m_buffer)
buffer.resize(samples_per_buffer);
SLresult result; SLresult result;
// create engine // create engine
result = slCreateEngine(&m_engine_object, 0, nullptr, 0, nullptr, nullptr); result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_engine_object)->Realize(m_engine_object, SL_BOOLEAN_FALSE); result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_engine_object)->GetInterface(m_engine_object, SL_IID_ENGINE, &m_engine_engine); result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_engine_engine)->CreateOutputMix(m_engine_engine, &m_output_mix_object, 0, 0, 0); result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_output_mix_object)->Realize(m_output_mix_object, SL_BOOLEAN_FALSE); result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM format_pcm = { SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,
SL_DATAFORMAT_PCM, channels, 2,
sample_rate * 1000, SL_PCMSAMPLEFORMAT_FIXED_16, m_mixer->GetSampleRate() * 1000,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_BYTEORDER_LITTLEENDIAN}; SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN};
SLDataSource audioSrc = {&loc_bufq, &format_pcm}; SLDataSource audioSrc = {&loc_bufq, &format_pcm};
// configure audio sink // configure audio sink
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, m_output_mix_object}; SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&loc_outmix, nullptr}; SLDataSink audioSnk = {&loc_outmix, nullptr};
// create audio player // create audio player
const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*m_engine_engine) result =
->CreateAudioPlayer(m_engine_engine, &m_bq_player_object, &audioSrc, &audioSnk, 2, (*engineEngine)
ids, req); ->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_object)->Realize(m_bq_player_object, SL_BOOLEAN_FALSE); result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_object)->GetInterface(m_bq_player_object, SL_IID_PLAY, &m_bq_player_play); result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_object)
->GetInterface(m_bq_player_object, SL_IID_BUFFERQUEUE, &m_bq_player_buffer_queue);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = result =
(*m_bq_player_object)->GetInterface(m_bq_player_object, SL_IID_VOLUME, &m_bq_player_volume); (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_buffer_queue) result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
->RegisterCallback(m_bq_player_buffer_queue, BQPlayerCallback, this);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
result = (*m_bq_player_play)->SetPlayState(m_bq_player_play, SL_PLAYSTATE_PLAYING); result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr);
ASSERT(SL_RESULT_SUCCESS == result);
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
ASSERT(SL_RESULT_SUCCESS == result); ASSERT(SL_RESULT_SUCCESS == result);
// Render and enqueue a first buffer. // Render and enqueue a first buffer.
m_current_buffer ^= 1; curBuffer ^= 1;
g_mixer = m_mixer.get();
result = (*m_bq_player_buffer_queue) result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[0], sizeof(buffer[0]));
->Enqueue(m_bq_player_buffer_queue, m_buffer[0].data(), m_bytes_per_buffer);
if (SL_RESULT_SUCCESS != result) if (SL_RESULT_SUCCESS != result)
return false; return false;
@ -118,39 +114,39 @@ bool OpenSLESStream::Init()
OpenSLESStream::~OpenSLESStream() OpenSLESStream::~OpenSLESStream()
{ {
if (m_bq_player_object != nullptr) if (bqPlayerObject != nullptr)
{ {
(*m_bq_player_object)->Destroy(m_bq_player_object); (*bqPlayerObject)->Destroy(bqPlayerObject);
m_bq_player_object = nullptr; bqPlayerObject = nullptr;
m_bq_player_play = nullptr; bqPlayerPlay = nullptr;
m_bq_player_buffer_queue = nullptr; bqPlayerBufferQueue = nullptr;
m_bq_player_volume = nullptr; bqPlayerVolume = nullptr;
} }
if (m_output_mix_object != nullptr) if (outputMixObject != nullptr)
{ {
(*m_output_mix_object)->Destroy(m_output_mix_object); (*outputMixObject)->Destroy(outputMixObject);
m_output_mix_object = nullptr; outputMixObject = nullptr;
} }
if (m_engine_object != nullptr) if (engineObject != nullptr)
{ {
(*m_engine_object)->Destroy(m_engine_object); (*engineObject)->Destroy(engineObject);
m_engine_object = nullptr; engineObject = nullptr;
m_engine_engine = nullptr; engineEngine = nullptr;
} }
} }
bool OpenSLESStream::SetRunning(bool running) bool OpenSLESStream::SetRunning(bool running)
{ {
SLuint32 new_state = running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED; SLuint32 new_state = running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED;
return (*m_bq_player_play)->SetPlayState(m_bq_player_play, new_state) == SL_RESULT_SUCCESS; return (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, new_state) == SL_RESULT_SUCCESS;
} }
void OpenSLESStream::SetVolume(int volume) void OpenSLESStream::SetVolume(int volume)
{ {
const SLmillibel attenuation = const SLmillibel attenuation =
volume <= 0 ? SL_MILLIBEL_MIN : static_cast<SLmillibel>(2000 * std::log10(volume / 100.0f)); volume <= 0 ? SL_MILLIBEL_MIN : static_cast<SLmillibel>(2000 * std::log10(volume / 100.0f));
(*m_bq_player_volume)->SetVolumeLevel(m_bq_player_volume, attenuation); (*bqPlayerVolume)->SetVolumeLevel(bqPlayerVolume, attenuation);
} }
#endif // HAVE_OPENSL_ES #endif // HAVE_OPENSL_ES

View File

@ -3,15 +3,10 @@
#pragma once #pragma once
#ifdef HAVE_OPENSL_ES #include <thread>
#include <array>
#include <vector>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#endif // HAVE_OPENSL_ES
#include "AudioCommon/SoundStream.h" #include "AudioCommon/SoundStream.h"
#include "Common/Event.h"
class OpenSLESStream final : public SoundStream class OpenSLESStream final : public SoundStream
{ {
@ -24,25 +19,7 @@ public:
static bool IsValid() { return true; } static bool IsValid() { return true; }
private: private:
static void BQPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context); std::thread thread;
void PushSamples(SLAndroidSimpleBufferQueueItf bq); Common::Event soundSyncEvent;
// engine interfaces
SLObjectItf m_engine_object;
SLEngineItf m_engine_engine;
SLObjectItf m_output_mix_object;
// buffer queue player interfaces
SLObjectItf m_bq_player_object = nullptr;
SLPlayItf m_bq_player_play;
SLAndroidSimpleBufferQueueItf m_bq_player_buffer_queue;
SLVolumeItf m_bq_player_volume;
SLuint32 m_frames_per_buffer;
SLuint32 m_bytes_per_buffer;
// Double buffering.
std::array<std::vector<short>, 2> m_buffer;
int m_current_buffer = 0;
#endif // HAVE_OPENSL_ES #endif // HAVE_OPENSL_ES
}; };

View File

@ -25,7 +25,6 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/ScopeGuard.h" #include "Common/ScopeGuard.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/TimeUtil.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
@ -96,7 +95,12 @@ int SDCardDiskIOCtl(File::IOFile* image, u8 pdrv, u8 cmd, void* buff)
u32 GetSystemTimeFAT() u32 GetSystemTimeFAT()
{ {
const std::time_t time = std::time(nullptr); const std::time_t time = std::time(nullptr);
std::tm tm = *Common::LocalTime(time); std::tm tm;
#ifdef _WIN32
localtime_s(&tm, &time);
#else
localtime_r(&time, &tm);
#endif
DWORD fattime = 0; DWORD fattime = 0;
fattime |= (tm.tm_year - 80) << 25; fattime |= (tm.tm_year - 80) << 25;

View File

@ -122,6 +122,7 @@ std::string SettingsWriter::GenerateSerialNumber()
// Must be 9 characters at most; otherwise the serial number will be rejected by SDK libraries, // Must be 9 characters at most; otherwise the serial number will be rejected by SDK libraries,
// as there is a check to ensure the string length is strictly lower than 10. // as there is a check to ensure the string length is strictly lower than 10.
return fmt::format("{:09}", t % 1000000000); // 3 for %j, 2 for %H, 2 for %M, 2 for %S.
return fmt::format("{:%j%H%M%S}", fmt::localtime(t));
} }
} // namespace Common } // namespace Common

View File

@ -2,25 +2,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/TimeUtil.h" #include "Common/TimeUtil.h"
#include "Common/Logging/Log.h"
#include <ctime> #include <ctime>
#include <optional> #include <optional>
namespace Common namespace Common
{ {
std::optional<std::tm> LocalTime(std::time_t time) std::optional<std::tm> Localtime(std::time_t time)
{ {
std::tm local_time; std::tm local_time;
#ifdef _MSC_VER #ifdef _MSC_VER
if (localtime_s(&local_time, &time) != 0) if (localtime_s(&local_time, &time) != 0)
#else
if (localtime_r(&time, &local_time) == NULL)
#endif
{
ERROR_LOG_FMT(COMMON, "Failed to convert time to local time: {}", std::strerror(errno));
return std::nullopt; return std::nullopt;
} #else
std::tm* result = localtime_r(&time, &local_time);
if (result != &local_time)
return std::nullopt;
#endif
return local_time; return local_time;
} }
} // Namespace Common } // Namespace Common

View File

@ -9,5 +9,5 @@
namespace Common namespace Common
{ {
// Threadsafe and error-checking variant of std::localtime() // Threadsafe and error-checking variant of std::localtime()
std::optional<std::tm> LocalTime(std::time_t time); std::optional<std::tm> Localtime(std::time_t time);
} // Namespace Common } // Namespace Common

View File

@ -8,7 +8,6 @@
#include <cstring> #include <cstring>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <optional>
#include <queue> #include <queue>
#include <utility> #include <utility>
#include <variant> #include <variant>
@ -35,7 +34,6 @@
#include "Common/ScopeGuard.h" #include "Common/ScopeGuard.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/Thread.h" #include "Common/Thread.h"
#include "Common/TimeUtil.h"
#include "Common/Version.h" #include "Common/Version.h"
#include "Core/AchievementManager.h" #include "Core/AchievementManager.h"
@ -735,17 +733,15 @@ static std::string GenerateScreenshotFolderPath()
return path; return path;
} }
static std::optional<std::string> GenerateScreenshotName() static std::string GenerateScreenshotName()
{ {
// append gameId, path only contains the folder here. // append gameId, path only contains the folder here.
const std::string path_prefix = const std::string path_prefix =
GenerateScreenshotFolderPath() + SConfig::GetInstance().GetGameID(); GenerateScreenshotFolderPath() + SConfig::GetInstance().GetGameID();
const std::time_t cur_time = std::time(nullptr); const std::time_t cur_time = std::time(nullptr);
const auto local_time = Common::LocalTime(cur_time); const std::string base_name =
if (!local_time) fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, fmt::localtime(cur_time));
return std::nullopt;
const std::string base_name = fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, *local_time);
// First try a filename without any suffixes, if already exists then append increasing numbers // First try a filename without any suffixes, if already exists then append increasing numbers
std::string name = fmt::format("{}.png", base_name); std::string name = fmt::format("{}.png", base_name);
@ -761,9 +757,7 @@ static std::optional<std::string> GenerateScreenshotName()
void SaveScreenShot() void SaveScreenShot()
{ {
const Core::CPUThreadGuard guard(Core::System::GetInstance()); const Core::CPUThreadGuard guard(Core::System::GetInstance());
std::optional<std::string> name = GenerateScreenshotName(); g_frame_dumper->SaveScreenshot(GenerateScreenshotName());
if (name)
g_frame_dumper->SaveScreenshot(*name);
} }
void SaveScreenShot(std::string_view name) void SaveScreenShot(std::string_view name)

View File

@ -16,7 +16,6 @@
#include "Common/Network.h" #include "Common/Network.h"
#include "Common/PcapFile.h" #include "Common/PcapFile.h"
#include "Common/ScopeGuard.h" #include "Common/ScopeGuard.h"
#include "Common/TimeUtil.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
@ -83,7 +82,7 @@ PCAPSSLCaptureLogger::PCAPSSLCaptureLogger()
{ {
const std::string filepath = const std::string filepath =
fmt::format("{}{} {:%Y-%m-%d %Hh%Mm%Ss}.pcap", File::GetUserPath(D_DUMPSSL_IDX), fmt::format("{}{} {:%Y-%m-%d %Hh%Mm%Ss}.pcap", File::GetUserPath(D_DUMPSSL_IDX),
SConfig::GetInstance().GetGameID(), *Common::LocalTime(std::time(nullptr))); SConfig::GetInstance().GetGameID(), fmt::localtime(std::time(nullptr)));
m_file = std::make_unique<Common::PCAP>( m_file = std::make_unique<Common::PCAP>(
new File::IOFile(filepath, "wb", File::SharedAccess::Read), Common::PCAP::LinkType::Ethernet); new File::IOFile(filepath, "wb", File::SharedAccess::Read), Common::PCAP::LinkType::Ethernet);
} }

View File

@ -281,7 +281,7 @@ static std::string SystemTimeAsDoubleToString(double time)
{ {
// revert adjustments from GetSystemTimeAsDouble() to get a normal Unix timestamp again // revert adjustments from GetSystemTimeAsDouble() to get a normal Unix timestamp again
const time_t seconds = static_cast<time_t>(time) + DOUBLE_TIME_OFFSET; const time_t seconds = static_cast<time_t>(time) + DOUBLE_TIME_OFFSET;
const auto local_time = Common::LocalTime(seconds); const auto local_time = Common::Localtime(seconds);
if (!local_time) if (!local_time)
return ""; return "";

View File

@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/FrameDumpFFMpeg.h" #include "VideoCommon/FrameDumpFFMpeg.h"
#include "Common/TimeUtil.h"
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
#define __STDC_CONSTANT_MACROS 1 #define __STDC_CONSTANT_MACROS 1
@ -125,15 +124,11 @@ std::string GetDumpPath(const std::string& extension, std::time_t time, u32 inde
if (!dump_path.empty()) if (!dump_path.empty())
return dump_path; return dump_path;
const auto local_time = Common::LocalTime(time);
if (!local_time)
return "";
const std::string path_prefix = const std::string path_prefix =
File::GetUserPath(D_DUMPFRAMES_IDX) + SConfig::GetInstance().GetGameID(); File::GetUserPath(D_DUMPFRAMES_IDX) + SConfig::GetInstance().GetGameID();
const std::string base_name = const std::string base_name =
fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}_{}", path_prefix, *local_time, index); fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}_{}", path_prefix, fmt::localtime(time), index);
const std::string path = fmt::format("{}.{}", base_name, extension); const std::string path = fmt::format("{}.{}", base_name, extension);