9#include <QtCore/qcoreapplication.h>
10#include <QtCore/qjniobject.h>
11#include <QtCore/qpermissions.h>
12#include <QtCore/private/qandroidextras_p.h>
15#define MINIMUM_PERIOD_TIME_MS 5
16#define DEFAULT_PERIOD_TIME_MS 50
18#define CheckError(message) if (result != SL_RESULT_SUCCESS) { qWarning(message); return; }
20#define SL_ANDROID_PCM_REPRESENTATION_INVALID 0
27 , m_checkedInputFormats(
false)
31 result = slCreateEngine(&m_engineObject, 0, 0, 0, 0, 0);
34 result = (*m_engineObject)->Realize(m_engineObject, SL_BOOLEAN_FALSE);
37 result = (*m_engineObject)->GetInterface(m_engineObject, SL_IID_ENGINE, &m_engine);
44 (*m_engineObject)->Destroy(m_engineObject);
49 return openslesEngine();
54 SLAndroidDataFormat_PCM_EX format_pcm;
55 format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
56 format_pcm.numChannels =
format.channelCount();
57 format_pcm.sampleRate =
format.sampleRate() * 1000;
58 format_pcm.bitsPerSample =
format.bytesPerSample() * 8;
59 format_pcm.containerSize =
format.bytesPerSample() * 8;
60 format_pcm.channelMask = (
format.channelCount() == 1 ?
61 SL_SPEAKER_FRONT_CENTER :
62 SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
64 SL_BYTEORDER_LITTLEENDIAN :
65 SL_BYTEORDER_BIGENDIAN);
67 switch (
format.sampleFormat()) {
69 format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
73 format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
76 format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
92 devs = QJniObject::callStaticObjectMethod(
93 "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
94 "getAudioInputDevices",
95 "()[Ljava/lang/String;");
97 devs = QJniObject::callStaticObjectMethod(
98 "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
99 "getAudioOutputDevices",
100 "()[Ljava/lang/String;");
102 if (devs.isValid()) {
104 jobjectArray devsArray =
static_cast<jobjectArray
>(devs.object());
105 const jint
size = env->GetArrayLength(devsArray);
106 for (
int i = 0;
i <
size; ++
i) {
118 return QJniObject::callStaticMethod<jboolean>(
119 "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
132 if (!m_checkedInputFormats)
134 return m_supportedInputChannelCounts;
143 if (!m_checkedInputFormats)
145 return m_supportedInputSampleRates;
147 return QList<int>() << 8000 << 11025 << 12000 << 16000 << 22050 << 24000
148 << 32000 << 44100 << 48000 << 64000 << 88200 << 96000 << 192000;
154 static int sampleRate = 0;
155 static int framesPerBuffer = 0;
158 return framesPerBuffer;
163 QJniObject ctx(QNativeInterface::QAndroidApplication::context());
168 QJniObject audioServiceString =
ctx.getStaticObjectField(
"android/content/Context",
170 "Ljava/lang/String;");
172 "(Ljava/lang/String;)Ljava/lang/Object;",
173 audioServiceString.object());
177 auto sampleRateField = QJniObject::getStaticObjectField(
"android/media/AudioManager",
178 "PROPERTY_OUTPUT_SAMPLE_RATE",
179 "Ljava/lang/String;");
180 auto framesPerBufferField = QJniObject::getStaticObjectField(
181 "android/media/AudioManager",
182 "PROPERTY_OUTPUT_FRAMES_PER_BUFFER",
183 "Ljava/lang/String;");
185 auto sampleRateString = am.callObjectMethod(
"getProperty",
186 "(Ljava/lang/String;)Ljava/lang/String;",
187 sampleRateField.object());
188 auto framesPerBufferString = am.callObjectMethod(
"getProperty",
189 "(Ljava/lang/String;)Ljava/lang/String;",
190 framesPerBufferField.object());
192 if (!sampleRateString.isValid() || !framesPerBufferString.isValid())
195 framesPerBuffer = framesPerBufferString.toString().toInt();
196 sampleRate = sampleRateString.toString().toInt();
199 return framesPerBuffer;
214 if (
format.channelCount() == 1)
216 else if (
format.channelCount() == 2)
218 else if (
format.channelCount() > 2)
224 const int audioFormat = [&
format]() ->
int
226 const int sdkVersion = QNativeInterface::QAndroidApplication::sdkVersion();
237 const int sampleRate =
format.sampleRate();
238 const int minBufferSize = QJniObject::callStaticMethod<jint>(
"android/media/AudioTrack",
255 static int isSupported = -1;
257 if (isSupported != -1)
258 return (isSupported == 1);
260 QJniObject ctx(QNativeInterface::QAndroidApplication::context());
264 QJniObject pm =
ctx.callObjectMethod(
"getPackageManager",
"()Landroid/content/pm/PackageManager;");
268 QJniObject audioFeatureField = QJniObject::getStaticObjectField(
269 "android/content/pm/PackageManager",
270 "FEATURE_AUDIO_LOW_LATENCY",
271 "Ljava/lang/String;");
272 if (!audioFeatureField.isValid())
275 isSupported = pm.callMethod<jboolean>(
"hasSystemFeature",
276 "(Ljava/lang/String;)Z",
277 audioFeatureField.object());
278 return (isSupported == 1);
286void QOpenSLESEngine::checkSupportedInputFormats()
288 m_supportedInputChannelCounts =
QList<int>() << 1;
289 m_supportedInputSampleRates.
clear();
291 SLAndroidDataFormat_PCM_EX defaultFormat;
292 defaultFormat.formatType = SL_DATAFORMAT_PCM;
293 defaultFormat.numChannels = 1;
294 defaultFormat.sampleRate = SL_SAMPLINGRATE_44_1;
295 defaultFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;
296 defaultFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_32;
297 defaultFormat.channelMask = SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(SL_SPEAKER_FRONT_CENTER);
298 defaultFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
299 defaultFormat.representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
301 const SLuint32
rates[13] = { SL_SAMPLINGRATE_8,
302 SL_SAMPLINGRATE_11_025,
305 SL_SAMPLINGRATE_22_05,
308 SL_SAMPLINGRATE_44_1,
311 SL_SAMPLINGRATE_88_2,
313 SL_SAMPLINGRATE_192 };
317 for (
size_t i = 0 ;
i < std::size(
rates); ++
i) {
318 SLAndroidDataFormat_PCM_EX
format = defaultFormat;
321 if (inputFormatIsSupported(
format))
328 SLAndroidDataFormat_PCM_EX
format = defaultFormat;
330 format.channelMask = SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(SL_SPEAKER_FRONT_LEFT
331 | SL_SPEAKER_FRONT_RIGHT);
332 if (inputFormatIsSupported(
format))
333 m_supportedInputChannelCounts.
append(2);
336 m_checkedInputFormats =
true;
339bool QOpenSLESEngine::inputFormatIsSupported(SLAndroidDataFormat_PCM_EX
format)
343 SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
344 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
345 SLDataSource audioSrc = { &loc_dev, NULL };
347 SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1 };
348 SLDataSink audioSnk = { &loc_bq, &
format };
354 result = (*m_engine)->CreateAudioRecorder(m_engine, &
recorder, &audioSrc, &audioSnk, 0, 0, 0);
355 if (
result == SL_RESULT_SUCCESS)
358 if (
result == SL_RESULT_SUCCESS) {
Mode
Describes the mode of this device.
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
void append(parameter_type t)
Access the microphone for monitoring or recording sound.
static int getLowLatencyBufferSize(const QAudioFormat &format)
static QOpenSLESEngine * instance()
static int getOutputValue(OutputValue type, int defaultValue=0)
static int getDefaultBufferSize(const QAudioFormat &format)
static SLAndroidDataFormat_PCM_EX audioFormatToSLFormatPCM(const QAudioFormat &format)
static QList< QAudioDevice > availableDevices(QAudioDevice::Mode mode)
static bool supportsLowLatency()
static bool printDebugInfo()
QList< int > supportedSampleRates(QAudioDevice::Mode mode) const
QList< int > supportedChannelCounts(QAudioDevice::Mode mode) const
static bool setAudioOutput(const QByteArray &deviceId)
\macro QT_RESTRICTED_CAST_FROM_ASCII
#define MINIMUM_PERIOD_TIME_MS
#define DEFAULT_PERIOD_TIME_MS
QAudioFormat::ChannelConfig channelConfig
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum format
GLuint GLsizei const GLenum * rates
static bool hasRecordPermission()
#define CheckError(message)
#define SL_ANDROID_PCM_REPRESENTATION_INVALID
#define QStringLiteral(str)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept