summaryrefslogtreecommitdiffstats
path: root/src/plugins/opensles/qopenslesengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/opensles/qopenslesengine.cpp')
-rw-r--r--src/plugins/opensles/qopenslesengine.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/plugins/opensles/qopenslesengine.cpp b/src/plugins/opensles/qopenslesengine.cpp
index 7689533e6..a30c90d84 100644
--- a/src/plugins/opensles/qopenslesengine.cpp
+++ b/src/plugins/opensles/qopenslesengine.cpp
@@ -38,8 +38,13 @@
#ifdef ANDROID
#include <SLES/OpenSLES_Android.h>
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/private/qjni_p.h>
#endif
+#define MINIMUM_PERIOD_TIME_MS 5
+#define DEFAULT_PERIOD_TIME_MS 50
+
#define CheckError(message) if (result != SL_RESULT_SUCCESS) { qWarning(message); return; }
Q_GLOBAL_STATIC(QOpenSLESEngine, openslesEngine);
@@ -130,6 +135,151 @@ QList<int> QOpenSLESEngine::supportedSampleRates(QAudio::Mode mode) const
}
}
+int QOpenSLESEngine::getOutputValue(QOpenSLESEngine::OutputValue type, int defaultValue)
+{
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK)
+ static int sampleRate = 0;
+ static int framesPerBuffer = 0;
+ static const int sdkVersion = QtAndroidPrivate::androidSdkVersion();
+
+ if (sdkVersion < 17) // getProperty() was added in API level 17...
+ return defaultValue;
+
+ if (type == FramesPerBuffer && framesPerBuffer != 0)
+ return framesPerBuffer;
+
+ if (type == SampleRate && sampleRate != 0)
+ return sampleRate;
+
+ QJNIObjectPrivate ctx(QtAndroidPrivate::activity());
+ if (!ctx.isValid())
+ return defaultValue;
+
+
+ QJNIObjectPrivate audioServiceString = ctx.getStaticObjectField("android/content/Context",
+ "AUDIO_SERVICE",
+ "Ljava/lang/String;");
+ QJNIObjectPrivate am = ctx.callObjectMethod("getSystemService",
+ "(Ljava/lang/String;)Ljava/lang/Object;",
+ audioServiceString.object());
+ if (!am.isValid())
+ return defaultValue;
+
+ QJNIObjectPrivate sampleRateField = QJNIObjectPrivate::getStaticObjectField("android/media/AudioManager",
+ "PROPERTY_OUTPUT_SAMPLE_RATE",
+ "Ljava/lang/String;");
+ QJNIObjectPrivate framesPerBufferField = QJNIObjectPrivate::getStaticObjectField("android/media/AudioManager",
+ "PROPERTY_OUTPUT_FRAMES_PER_BUFFER",
+ "Ljava/lang/String;");
+
+ QJNIObjectPrivate sampleRateString = am.callObjectMethod("getProperty",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ sampleRateField.object());
+ QJNIObjectPrivate framesPerBufferString = am.callObjectMethod("getProperty",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ framesPerBufferField.object());
+
+ if (!sampleRateString.isValid() || !framesPerBufferString.isValid())
+ return defaultValue;
+
+ framesPerBuffer = framesPerBufferString.toString().toInt();
+ sampleRate = sampleRateString.toString().toInt();
+
+ if (type == FramesPerBuffer)
+ return framesPerBuffer;
+
+ if (type == SampleRate)
+ return sampleRate;
+
+#endif // Q_OS_ANDROID
+
+ return defaultValue;
+}
+
+int QOpenSLESEngine::getDefaultBufferSize(const QAudioFormat &format)
+{
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK)
+ if (!format.isValid())
+ return 0;
+
+ const int channelConfig = [&format]() -> int
+ {
+ if (format.channelCount() == 1)
+ return 4; /* MONO */
+ else if (format.channelCount() == 2)
+ return 12; /* STEREO */
+ else if (format.channelCount() > 2)
+ return 1052; /* SURROUND */
+ else
+ return 1; /* DEFAULT */
+ }();
+
+ const int audioFormat = [&format]() -> int
+ {
+ if (format.sampleType() == QAudioFormat::Float && QtAndroidPrivate::androidSdkVersion() >= 21)
+ return 4; /* PCM_FLOAT */
+ else if (format.sampleSize() == 8)
+ return 3; /* PCM_8BIT */
+ else if (format.sampleSize() == 16)
+ return 2; /* PCM_16BIT*/
+ else
+ return 1; /* DEFAULT */
+ }();
+
+ const int sampleRate = format.sampleRate();
+ return QJNIObjectPrivate::callStaticMethod<jint>("android/media/AudioTrack",
+ "getMinBufferSize",
+ "(III)I",
+ sampleRate,
+ channelConfig,
+ audioFormat);
+#else
+ return format.bytesForDuration(DEFAULT_PERIOD_TIME_MS);
+#endif // Q_OS_ANDROID
+}
+
+int QOpenSLESEngine::getLowLatencyBufferSize(const QAudioFormat &format)
+{
+ return format.bytesForFrames(QOpenSLESEngine::getOutputValue(QOpenSLESEngine::FramesPerBuffer,
+ format.framesForDuration(MINIMUM_PERIOD_TIME_MS)));
+}
+
+bool QOpenSLESEngine::supportsLowLatency()
+{
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK)
+ static int isSupported = -1;
+
+ if (isSupported != -1)
+ return (isSupported == 1);
+
+ QJNIObjectPrivate ctx(QtAndroidPrivate::activity());
+ if (!ctx.isValid())
+ return false;
+
+ QJNIObjectPrivate pm = ctx.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
+ if (!pm.isValid())
+ return false;
+
+ QJNIObjectPrivate audioFeatureField = QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager",
+ "FEATURE_AUDIO_LOW_LATENCY",
+ "Ljava/lang/String;");
+ if (!audioFeatureField.isValid())
+ return false;
+
+ isSupported = pm.callMethod<jboolean>("hasSystemFeature",
+ "(Ljava/lang/String;)Z",
+ audioFeatureField.object());
+ return (isSupported == 1);
+#else
+ return true;
+#endif // Q_OS_ANDROID
+}
+
+bool QOpenSLESEngine::printDebugInfo()
+{
+ return qEnvironmentVariableIsSet("QT_OPENSL_INFO");
+}
+
void QOpenSLESEngine::checkSupportedInputFormats()
{
m_supportedInputChannelCounts = QList<int>() << 1;