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 switch (channelCount) {
55 case 1:
return SL_SPEAKER_FRONT_CENTER;
56 case 2:
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
57 case 3:
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER;
58 case 4:
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT
59 | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
60 case 5:
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT
61 | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_FRONT_CENTER;
62 case 6:
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT
63 | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY;
70 SLAndroidDataFormat_PCM_EX format_pcm;
71 format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
72 format_pcm.numChannels =
format.channelCount();
73 format_pcm.sampleRate =
format.sampleRate() * 1000;
74 format_pcm.bitsPerSample =
format.bytesPerSample() * 8;
75 format_pcm.containerSize =
format.bytesPerSample() * 8;
78 SL_BYTEORDER_LITTLEENDIAN :
79 SL_BYTEORDER_BIGENDIAN);
81 switch (
format.sampleFormat()) {
83 format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
87 format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
90 format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
106 devs = QJniObject::callStaticObjectMethod(
107 "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
108 "getAudioInputDevices",
109 "()[Ljava/lang/String;");
111 devs = QJniObject::callStaticObjectMethod(
112 "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
113 "getAudioOutputDevices",
114 "()[Ljava/lang/String;");
116 if (devs.isValid()) {
118 jobjectArray devsArray =
static_cast<jobjectArray
>(devs.object());
119 const jint
size = env->GetArrayLength(devsArray);
120 for (
int i = 0;
i <
size; ++
i) {
132 return QJniObject::callStaticMethod<jboolean>(
133 "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
146 if (!m_checkedInputFormats)
148 return m_supportedInputChannelCounts;
150 return QList<int>() << 1 << 2;
157 if (!m_checkedInputFormats)
159 return m_supportedInputSampleRates;
161 return QList<int>() << 8000 << 11025 << 12000 << 16000 << 22050 << 24000
162 << 32000 << 44100 << 48000 << 64000 << 88200 << 96000 << 192000;
168 static int sampleRate = 0;
169 static int framesPerBuffer = 0;
172 return framesPerBuffer;
177 QJniObject ctx(QNativeInterface::QAndroidApplication::context());
182 QJniObject audioServiceString =
ctx.getStaticObjectField(
"android/content/Context",
184 "Ljava/lang/String;");
186 "(Ljava/lang/String;)Ljava/lang/Object;",
187 audioServiceString.object());
191 auto sampleRateField = QJniObject::getStaticObjectField(
"android/media/AudioManager",
192 "PROPERTY_OUTPUT_SAMPLE_RATE",
193 "Ljava/lang/String;");
194 auto framesPerBufferField = QJniObject::getStaticObjectField(
195 "android/media/AudioManager",
196 "PROPERTY_OUTPUT_FRAMES_PER_BUFFER",
197 "Ljava/lang/String;");
199 auto sampleRateString = am.callObjectMethod(
"getProperty",
200 "(Ljava/lang/String;)Ljava/lang/String;",
201 sampleRateField.object());
202 auto framesPerBufferString = am.callObjectMethod(
"getProperty",
203 "(Ljava/lang/String;)Ljava/lang/String;",
204 framesPerBufferField.object());
206 if (!sampleRateString.isValid() || !framesPerBufferString.isValid())
209 framesPerBuffer = framesPerBufferString.toString().toInt();
210 sampleRate = sampleRateString.toString().toInt();
213 return framesPerBuffer;
228 if (
format.channelCount() == 1)
230 else if (
format.channelCount() == 2)
232 else if (
format.channelCount() > 2)
238 const int audioFormat = [&
format]() ->
int
240 const int sdkVersion = QNativeInterface::QAndroidApplication::sdkVersion();
251 const int sampleRate =
format.sampleRate();
252 const int minBufferSize = QJniObject::callStaticMethod<jint>(
"android/media/AudioTrack",
269 static int isSupported = -1;
271 if (isSupported != -1)
272 return (isSupported == 1);
274 QJniObject ctx(QNativeInterface::QAndroidApplication::context());
278 QJniObject pm =
ctx.callObjectMethod(
"getPackageManager",
"()Landroid/content/pm/PackageManager;");
282 QJniObject audioFeatureField = QJniObject::getStaticObjectField(
283 "android/content/pm/PackageManager",
284 "FEATURE_AUDIO_LOW_LATENCY",
285 "Ljava/lang/String;");
286 if (!audioFeatureField.isValid())
289 isSupported = pm.callMethod<jboolean>(
"hasSystemFeature",
290 "(Ljava/lang/String;)Z",
291 audioFeatureField.object());
292 return (isSupported == 1);
300void QOpenSLESEngine::checkSupportedInputFormats()
302 m_supportedInputChannelCounts = QList<int>() << 1;
303 m_supportedInputSampleRates.
clear();
305 SLAndroidDataFormat_PCM_EX defaultFormat;
306 defaultFormat.formatType = SL_DATAFORMAT_PCM;
307 defaultFormat.numChannels = 1;
308 defaultFormat.sampleRate = SL_SAMPLINGRATE_44_1;
309 defaultFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;
310 defaultFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_32;
311 defaultFormat.channelMask = SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(SL_SPEAKER_FRONT_CENTER);
312 defaultFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
313 defaultFormat.representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
315 const SLuint32
rates[13] = { SL_SAMPLINGRATE_8,
316 SL_SAMPLINGRATE_11_025,
319 SL_SAMPLINGRATE_22_05,
322 SL_SAMPLINGRATE_44_1,
325 SL_SAMPLINGRATE_88_2,
327 SL_SAMPLINGRATE_192 };
331 for (
size_t i = 0 ;
i < std::size(
rates); ++
i) {
332 SLAndroidDataFormat_PCM_EX
format = defaultFormat;
335 if (inputFormatIsSupported(
format))
342 SLAndroidDataFormat_PCM_EX
format = defaultFormat;
344 format.channelMask = SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(SL_SPEAKER_FRONT_LEFT
345 | SL_SPEAKER_FRONT_RIGHT);
346 if (inputFormatIsSupported(
format))
347 m_supportedInputChannelCounts.
append(2);
350 m_checkedInputFormats =
true;
353bool QOpenSLESEngine::inputFormatIsSupported(SLAndroidDataFormat_PCM_EX
format)
357 SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
358 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
359 SLDataSource audioSrc = { &loc_dev, NULL };
361 SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1 };
362 SLDataSink audioSnk = { &loc_bq, &
format };
368 result = (*m_engine)->CreateAudioRecorder(m_engine, &
recorder, &audioSrc, &audioSnk, 0, 0, 0);
369 if (
result == SL_RESULT_SUCCESS)
372 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()
static SLuint32 getChannelMask(unsigned channelCount)
#define CheckError(message)
#define SL_ANDROID_PCM_REPRESENTATION_INVALID
#define QStringLiteral(str)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept