11#include <SLES/OpenSLES_Android.h>
12#include <SLES/OpenSLES_AndroidConfiguration.h>
20 qDebug() <<
"======= OpenSL ES Device info ======="
24 <<
"\nPreferred Format: " <<
format
36 m_streamType = SL_ANDROID_STREAM_MEDIA;
70 m_availableBuffers = BufferCount;
75 for (
int i = 0;
i != BufferCount; ++
i) {
76 const int index =
i * m_bufferSize;
77 const qint64 readSize = m_audioSource->
read(m_buffers +
index, m_bufferSize);
78 if (readSize && SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
85 m_processedBytes += readSize;
88 if (m_processedBytes < 1)
97void QAndroidAudioSink::readyRead()
111 if (!preparePlayer())
115 m_processedBytes = 0;
116 m_availableBuffers = BufferCount;
124 return m_audioSource;
141 return m_availableBuffers.
loadAcquire() ? m_bufferSize : 0;
149 m_startRequiresInit =
true;
150 m_bufferSize =
value;
163 SLmillisecond processMSec = 0;
165 (*m_playItf)->GetPosition(m_playItf, &processMSec);
167 return processMSec * 1000;
175 if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) {
181 setState(m_suspendedInState);
187 m_startRequiresInit =
true;
201 if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PAUSED)) {
207 m_suspendedInState = m_state;
220 const SLmillibel newVolume = adjustVolume(m_volume);
221 if (m_volumeItf && SL_RESULT_SUCCESS != (*m_volumeItf)->SetVolumeLevel(m_volumeItf, newVolume))
222 qWarning() <<
"Unable to change volume";
230void QAndroidAudioSink::onEOSEvent()
235 SLBufferQueueState
state;
236 if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->GetState(m_bufferQueueItf, &
state))
246void QAndroidAudioSink::onBytesProcessed(
qint64 bytes)
248 m_processedBytes += bytes;
251void QAndroidAudioSink::bufferAvailable()
259 if (
val == BufferCount)
266 const int index = m_nextBuffer * m_bufferSize;
268 if (m_audioSource->
atEnd()) {
278 readSize = m_bufferSize;
279 memset(m_buffers +
index, 0, readSize);
281 readSize = m_audioSource->
read(m_buffers +
index, m_bufferSize);
291 if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
299 m_nextBuffer = (m_nextBuffer + 1) % BufferCount;
305void QAndroidAudioSink::playCallback(SLPlayItf
player,
void *
ctx, SLuint32
event)
309 if (
event & SL_PLAYEVENT_HEADATEND)
313void QAndroidAudioSink::bufferQueueCallback(SLBufferQueueItf bufferQueue,
void *
ctx)
320bool QAndroidAudioSink::preparePlayer()
322 if (m_startRequiresInit)
328 qWarning() <<
"Unable to set up Audio Output Device";
337 SLDataLocator_BufferQueue bufferQueueLocator = { SL_DATALOCATOR_BUFFERQUEUE, BufferCount };
340 SLDataSource audioSrc = { &bufferQueueLocator, &pcmFormat };
343 if (SL_RESULT_SUCCESS != (*engine)->CreateOutputMix(
engine,
348 qWarning() <<
"Unable to create output mix";
353 if (SL_RESULT_SUCCESS != (*m_outputMixObject)->Realize(m_outputMixObject, SL_BOOLEAN_FALSE)) {
354 qWarning() <<
"Unable to initialize output mix";
359 SLDataLocator_OutputMix outputMixLocator = { SL_DATALOCATOR_OUTPUTMIX, m_outputMixObject };
360 SLDataSink audioSink = { &outputMixLocator,
nullptr };
364 const SLInterfaceID
ids[iids] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME };
365 const SLboolean req[iids] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
368 const SLInterfaceID
ids[iids] = { SL_IID_BUFFERQUEUE,
370 SL_IID_ANDROIDCONFIGURATION };
371 const SLboolean req[iids] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
375 if (SL_RESULT_SUCCESS != (*engine)->CreateAudioPlayer(
engine,
382 qWarning() <<
"Unable to create AudioPlayer";
389 SLAndroidConfigurationItf playerConfig;
390 if (SL_RESULT_SUCCESS == (*m_playerObject)->GetInterface(m_playerObject,
391 SL_IID_ANDROIDCONFIGURATION,
393 (*playerConfig)->SetConfiguration(playerConfig,
394 SL_ANDROID_KEY_STREAM_TYPE,
400 if (SL_RESULT_SUCCESS != (*m_playerObject)->Realize(m_playerObject, SL_BOOLEAN_FALSE)) {
401 qWarning() <<
"Unable to initialize AudioPlayer";
407 if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
409 &m_bufferQueueItf)) {
414 if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->RegisterCallback(m_bufferQueueItf,
422 if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
429 if (SL_RESULT_SUCCESS != (*m_playItf)->RegisterCallback(m_playItf, playCallback,
this)) {
434 if (SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, m_eventMask)) {
440 if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
459 if (m_bufferSize <= 0) {
462 if (m_bufferSize < lowLatencyBufferSize)
463 m_bufferSize = lowLatencyBufferSize;
469 m_buffers =
new char[BufferCount * m_bufferSize];
472 m_startRequiresInit =
false;
477void QAndroidAudioSink::destroyPlayer()
482 if (m_playerObject) {
483 (*m_playerObject)->Destroy(m_playerObject);
484 m_playerObject =
nullptr;
487 if (m_outputMixObject) {
488 (*m_outputMixObject)->Destroy(m_outputMixObject);
489 m_outputMixObject =
nullptr;
492 if (!m_pullMode && m_audioSource) {
493 m_audioSource->
close();
494 delete m_audioSource;
495 m_audioSource =
nullptr;
500 m_processedBytes = 0;
504 m_volumeItf =
nullptr;
505 m_bufferQueueItf =
nullptr;
506 m_startRequiresInit =
true;
509void QAndroidAudioSink::stopPlayer()
517 m_audioSource->
close();
518 delete m_audioSource;
519 m_audioSource =
nullptr;
525 (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_STOPPED);
527 if (m_bufferQueueItf && SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Clear(m_bufferQueueItf))
528 qWarning() <<
"Unable to clear buffer";
531void QAndroidAudioSink::startPlayer()
536 if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) {
547 if (
len > m_bufferSize)
559 const int index = m_nextBuffer * m_bufferSize;
561 const SLuint32
res = (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
566 if (
res == SL_RESULT_BUFFER_INSUFFICIENT) {
571 if (
res != SL_RESULT_SUCCESS) {
577 m_processedBytes +=
len;
580 m_nextBuffer = (m_nextBuffer + 1) % BufferCount;
587 if (m_state ==
state)
596 if (m_error ==
error)
603inline SLmillibel QAndroidAudioSink::adjustVolume(
qreal vol)
606 return SL_MILLIBEL_MIN;
IOBluetoothDevice * device
qsizetype bytesFree() const override
void setVolume(qreal volume) override
qsizetype bufferSize() const override
friend class SLIODevicePrivate
QIODevice * start() override
QAudioFormat format() const override
QAudio::Error error() const override
QAudio::State state() const override
QAndroidAudioSink(const QByteArray &device, QObject *parent)
qint64 processedUSecs() const override
qreal volume() const override
void setFormat(const QAudioFormat &format) override
void setBufferSize(qsizetype value) override
QAudioFormat preferredFormat() const
Returns the default audio format settings for this device.
void stateChanged(QAudio::State state)
void errorChanged(QAudio::Error error)
T fetchAndAddAcquire(T valueToAdd) noexcept
T loadAcquire() const noexcept
T fetchAndAddRelease(T valueToAdd) noexcept
void storeRelease(T newValue) noexcept
\inmodule QtCore \reentrant
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
void readyRead()
This signal is emitted once every time new data is available for reading from the device's current re...
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
virtual bool atEnd() const
Returns true if the current read and write position is at the end of the device (i....
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
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 bool supportsLowLatency()
static bool printDebugInfo()
static bool setAudioOutput(const QByteArray &deviceId)
Q_MULTIMEDIA_EXPORT float convertVolume(float volume, VolumeScale from, VolumeScale to)
Converts an audio volume from a volume scale to another, and returns the result.
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE void openSlDebugInfo()
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
bool qFuzzyIsNull(qfloat16 f) noexcept
constexpr const T & qBound(const T &min, const T &val, const T &max)
#define Q_ARG(Type, data)
GLenum GLenum GLsizei const GLuint * ids
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
static const int defaultBufferSize
myObject disconnect()
[26]