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;
69 m_availableBuffers = BufferCount;
74 for (
int i = 0;
i != BufferCount; ++
i) {
75 const int index =
i * m_bufferSize;
76 const qint64 readSize = m_audioSource->
read(m_buffers +
index, m_bufferSize);
77 if (readSize && SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
84 m_processedBytes += readSize;
87 if (m_processedBytes < 1)
96void QAndroidAudioSink::readyRead()
110 if (!preparePlayer())
114 m_processedBytes = 0;
115 m_availableBuffers = BufferCount;
123 return m_audioSource;
140 return m_availableBuffers.
loadAcquire() ? m_bufferSize : 0;
148 m_startRequiresInit =
true;
149 m_bufferSize =
value;
162 SLmillisecond processMSec = 0;
164 (*m_playItf)->GetPosition(m_playItf, &processMSec);
166 return processMSec * 1000;
174 if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) {
180 setState(m_suspendedInState);
186 m_startRequiresInit =
true;
200 if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PAUSED)) {
206 m_suspendedInState = m_state;
219 const SLmillibel newVolume = adjustVolume(m_volume);
220 if (m_volumeItf && SL_RESULT_SUCCESS != (*m_volumeItf)->SetVolumeLevel(m_volumeItf, newVolume))
221 qWarning() <<
"Unable to change volume";
229void QAndroidAudioSink::onEOSEvent()
234 SLBufferQueueState
state;
235 if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->GetState(m_bufferQueueItf, &
state))
245void QAndroidAudioSink::onBytesProcessed(
qint64 bytes)
247 m_processedBytes += bytes;
250void QAndroidAudioSink::bufferAvailable()
258 if (
val == BufferCount)
265 const int index = m_nextBuffer * m_bufferSize;
266 const qint64 readSize = m_audioSource->
read(m_buffers +
index, m_bufferSize);
274 if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
282 m_nextBuffer = (m_nextBuffer + 1) % BufferCount;
285 if (m_audioSource->
atEnd())
289void QAndroidAudioSink::playCallback(SLPlayItf
player,
void *
ctx, SLuint32
event)
293 if (
event & SL_PLAYEVENT_HEADATEND)
297void QAndroidAudioSink::bufferQueueCallback(SLBufferQueueItf bufferQueue,
void *
ctx)
301 audioOutput->bufferAvailable();
304bool QAndroidAudioSink::preparePlayer()
306 if (m_startRequiresInit)
312 qWarning() <<
"Unable to set up Audio Output Device";
321 SLDataLocator_BufferQueue bufferQueueLocator = { SL_DATALOCATOR_BUFFERQUEUE, BufferCount };
324 SLDataSource audioSrc = { &bufferQueueLocator, &pcmFormat };
327 if (SL_RESULT_SUCCESS != (*engine)->CreateOutputMix(
engine,
332 qWarning() <<
"Unable to create output mix";
337 if (SL_RESULT_SUCCESS != (*m_outputMixObject)->Realize(m_outputMixObject, SL_BOOLEAN_FALSE)) {
338 qWarning() <<
"Unable to initialize output mix";
343 SLDataLocator_OutputMix outputMixLocator = { SL_DATALOCATOR_OUTPUTMIX, m_outputMixObject };
344 SLDataSink audioSink = { &outputMixLocator,
nullptr };
348 const SLInterfaceID
ids[iids] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME };
349 const SLboolean req[iids] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
352 const SLInterfaceID
ids[iids] = { SL_IID_BUFFERQUEUE,
354 SL_IID_ANDROIDCONFIGURATION };
355 const SLboolean req[iids] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
359 if (SL_RESULT_SUCCESS != (*engine)->CreateAudioPlayer(
engine,
366 qWarning() <<
"Unable to create AudioPlayer";
373 SLAndroidConfigurationItf playerConfig;
374 if (SL_RESULT_SUCCESS == (*m_playerObject)->GetInterface(m_playerObject,
375 SL_IID_ANDROIDCONFIGURATION,
377 (*playerConfig)->SetConfiguration(playerConfig,
378 SL_ANDROID_KEY_STREAM_TYPE,
384 if (SL_RESULT_SUCCESS != (*m_playerObject)->Realize(m_playerObject, SL_BOOLEAN_FALSE)) {
385 qWarning() <<
"Unable to initialize AudioPlayer";
391 if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
393 &m_bufferQueueItf)) {
398 if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->RegisterCallback(m_bufferQueueItf,
406 if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
413 if (SL_RESULT_SUCCESS != (*m_playItf)->RegisterCallback(m_playItf, playCallback,
this)) {
418 if (SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, m_eventMask)) {
424 if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
443 if (m_bufferSize <= 0) {
446 if (m_bufferSize < lowLatencyBufferSize)
447 m_bufferSize = lowLatencyBufferSize;
453 m_buffers =
new char[BufferCount * m_bufferSize];
456 m_startRequiresInit =
false;
461void QAndroidAudioSink::destroyPlayer()
466 if (m_playerObject) {
467 (*m_playerObject)->Destroy(m_playerObject);
468 m_playerObject =
nullptr;
471 if (m_outputMixObject) {
472 (*m_outputMixObject)->Destroy(m_outputMixObject);
473 m_outputMixObject =
nullptr;
476 if (!m_pullMode && m_audioSource) {
477 m_audioSource->
close();
478 delete m_audioSource;
479 m_audioSource =
nullptr;
484 m_processedBytes = 0;
488 m_volumeItf =
nullptr;
489 m_bufferQueueItf =
nullptr;
490 m_startRequiresInit =
true;
493void QAndroidAudioSink::stopPlayer()
501 m_audioSource->
close();
502 delete m_audioSource;
503 m_audioSource =
nullptr;
509 (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_STOPPED);
511 if (m_bufferQueueItf && SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Clear(m_bufferQueueItf))
512 qWarning() <<
"Unable to clear buffer";
515void QAndroidAudioSink::startPlayer()
520 if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) {
531 if (
len > m_bufferSize)
543 const int index = m_nextBuffer * m_bufferSize;
545 const SLuint32
res = (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
550 if (
res == SL_RESULT_BUFFER_INSUFFICIENT) {
555 if (
res != SL_RESULT_SUCCESS) {
561 m_processedBytes +=
len;
564 m_nextBuffer = (m_nextBuffer + 1) % BufferCount;
571 if (m_state ==
state)
580 if (m_error ==
error)
587inline SLmillibel QAndroidAudioSink::adjustVolume(
qreal vol)
590 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.
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)
SLEngineItf slEngine() const
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)
State
\value ActiveState Audio data is being processed, this state is set after start() is called and while...
Error
\value NoError No errors have occurred \value OpenError An error occurred opening the audio device \v...
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]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent