diff options
Diffstat (limited to 'src/plugins/opensles/qopenslesengine.cpp')
-rw-r--r-- | src/plugins/opensles/qopenslesengine.cpp | 150 |
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; |