summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/AudioUtils.kt28
-rw-r--r--Source/Android/jni/AndroidCommon/IDCache.cpp27
-rw-r--r--Source/Android/jni/AndroidCommon/IDCache.h4
-rw-r--r--Source/Core/AudioCommon/OpenSLESStream.cpp37
-rw-r--r--Source/Core/AudioCommon/OpenSLESStream.h9
5 files changed, 92 insertions, 13 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/AudioUtils.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/AudioUtils.kt
new file mode 100644
index 0000000000..68e3573fa5
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/AudioUtils.kt
@@ -0,0 +1,28 @@
+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
+ }
+ }
+}
diff --git a/Source/Android/jni/AndroidCommon/IDCache.cpp b/Source/Android/jni/AndroidCommon/IDCache.cpp
index 08ec2c9804..d8dfa2b7c4 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.cpp
+++ b/Source/Android/jni/AndroidCommon/IDCache.cpp
@@ -122,6 +122,10 @@ static jmethodID s_permission_handler_request_record_audio_permission;
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
{
JNIEnv* GetEnvForThread()
@@ -562,6 +566,21 @@ jmethodID GetRunnableRun()
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
extern "C" {
@@ -798,6 +817,13 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
s_runnable_run = env->GetMethodID(runnable_class, "run", "()V");
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;
}
@@ -834,5 +860,6 @@ JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
env->DeleteGlobalRef(s_core_device_control_class);
env->DeleteGlobalRef(s_input_detector_class);
env->DeleteGlobalRef(s_permission_handler_class);
+ env->DeleteGlobalRef(s_audio_utils_class);
}
}
diff --git a/Source/Android/jni/AndroidCommon/IDCache.h b/Source/Android/jni/AndroidCommon/IDCache.h
index 3cc8c11b5e..e44e68e431 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.h
+++ b/Source/Android/jni/AndroidCommon/IDCache.h
@@ -121,4 +121,8 @@ jmethodID GetPermissionHandlerRequestRecordAudioPermission();
jmethodID GetRunnableRun();
+jclass GetAudioUtilsClass();
+jmethodID GetAudioUtilsGetSampleRate();
+jmethodID GetAudioUtilsGetFramesPerBuffer();
+
} // namespace IDCache
diff --git a/Source/Core/AudioCommon/OpenSLESStream.cpp b/Source/Core/AudioCommon/OpenSLESStream.cpp
index 84831ceec6..3fc71e75df 100644
--- a/Source/Core/AudioCommon/OpenSLESStream.cpp
+++ b/Source/Core/AudioCommon/OpenSLESStream.cpp
@@ -8,11 +8,13 @@
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
+#include <jni.h>
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/ConfigManager.h"
+#include "jni/AndroidCommon/IDCache.h"
void OpenSLESStream::BQPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
{
@@ -24,8 +26,8 @@ void OpenSLESStream::PushSamples(SLAndroidSimpleBufferQueueItf bq)
ASSERT(bq == m_bq_player_buffer_queue);
// Render to the fresh buffer
- m_mixer->Mix(reinterpret_cast<short*>(m_buffer[m_current_buffer]), BUFFER_SIZE_IN_SAMPLES);
- SLresult result = (*bq)->Enqueue(bq, m_buffer[m_current_buffer], sizeof(m_buffer[0]));
+ m_mixer->Mix(m_buffer[m_current_buffer].data(), m_frames_per_buffer);
+ SLresult result = (*bq)->Enqueue(bq, m_buffer[m_current_buffer].data(), m_bytes_per_buffer);
m_current_buffer ^= 1; // Switch buffer
// Comment from sample code:
@@ -36,6 +38,23 @@ void OpenSLESStream::PushSamples(SLAndroidSimpleBufferQueueItf bq)
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;
// create engine
result = slCreateEngine(&m_engine_object, 0, nullptr, 0, nullptr, nullptr);
@@ -50,13 +69,11 @@ bool OpenSLESStream::Init()
ASSERT(SL_RESULT_SUCCESS == result);
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
- SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,
- 2,
- m_mixer->GetSampleRate() * 1000,
- SL_PCMSAMPLEFORMAT_FIXED_16,
- SL_PCMSAMPLEFORMAT_FIXED_16,
- SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
- SL_BYTEORDER_LITTLEENDIAN};
+ SLDataFormat_PCM format_pcm = {
+ SL_DATAFORMAT_PCM, channels,
+ sample_rate * 1000, SL_PCMSAMPLEFORMAT_FIXED_16,
+ SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
+ SL_BYTEORDER_LITTLEENDIAN};
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
@@ -92,7 +109,7 @@ bool OpenSLESStream::Init()
m_current_buffer ^= 1;
result = (*m_bq_player_buffer_queue)
- ->Enqueue(m_bq_player_buffer_queue, m_buffer[0], sizeof(m_buffer[0]));
+ ->Enqueue(m_bq_player_buffer_queue, m_buffer[0].data(), m_bytes_per_buffer);
if (SL_RESULT_SUCCESS != result)
return false;
diff --git a/Source/Core/AudioCommon/OpenSLESStream.h b/Source/Core/AudioCommon/OpenSLESStream.h
index 009d8d891a..9772f0b9c7 100644
--- a/Source/Core/AudioCommon/OpenSLESStream.h
+++ b/Source/Core/AudioCommon/OpenSLESStream.h
@@ -4,6 +4,9 @@
#pragma once
#ifdef HAVE_OPENSL_ES
+#include <array>
+#include <vector>
+
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#endif // HAVE_OPENSL_ES
@@ -35,11 +38,11 @@ private:
SLAndroidSimpleBufferQueueItf m_bq_player_buffer_queue;
SLVolumeItf m_bq_player_volume;
- static constexpr int BUFFER_SIZE = 512;
- static constexpr int BUFFER_SIZE_IN_SAMPLES = BUFFER_SIZE / 2;
+ SLuint32 m_frames_per_buffer;
+ SLuint32 m_bytes_per_buffer;
// Double buffering.
- short m_buffer[2][BUFFER_SIZE];
+ std::array<std::vector<short>, 2> m_buffer;
int m_current_buffer = 0;
#endif // HAVE_OPENSL_ES
};