15#define AL_FORMAT_MONO_FLOAT32 0x10010
16#define AL_FORMAT_STEREO_FLOAT32 0x10011
56 m_device->
write(
nullptr, 0);
87 auto formatError = [
this](){
88 qWarning() <<
"Unsupported audio format " << m_format;
95 aldata->
format = AL_FORMAT_MONO8;
98 aldata->
format = AL_FORMAT_STEREO8;
101 return formatError();
107 aldata->
format = AL_FORMAT_MONO16;
110 aldata->
format = AL_FORMAT_STEREO16;
113 return formatError();
125 return formatError();
129 return formatError();
133 aldata->
device = alcOpenDevice(m_name.
data());
135 qWarning() <<
"Failed to open audio device" << alGetString(alGetError());
138 ALint attrlist[] = {ALC_FREQUENCY, m_format.
sampleRate(), 0};
139 aldata->
context = alcCreateContext(aldata->
device, attrlist);
142 qWarning() <<
"Failed to create audio context" << alGetString(alGetError());
145 alcMakeContextCurrent(aldata->
context);
147 alGenSources(1, &aldata->
source);
149 if (m_bufferSize > 0)
150 m_bufferFragmentsCount =
qMax(2,
qCeil((
qreal)m_bufferSize/(m_bufferFragmentSize)));
151 m_bufferSize = m_bufferFragmentsCount * m_bufferFragmentSize;
152 aldata->
buffers =
new ALuint[m_bufferFragmentsCount];
154 alGenBuffers(m_bufferFragmentsCount, aldata->
buffers);
158 alSourcef(aldata->
source, AL_GAIN, m_volume);
164 alSourcePlay(aldata->
source);
166 m_elapsedTimer.
start();
175 alSourceStop(aldata->
source);
176 alSourceRewind(aldata->
source);
178 m_bufferFragmentsBusyCount = 0;
179 alDeleteSources(1, &aldata->
source);
180 alDeleteBuffers(m_bufferFragmentsCount, aldata->
buffers);
182 alcMakeContextCurrent(
nullptr);
183 alcDestroyContext(aldata->
context);
184 alcCloseDevice(aldata->
device);
203 m_suspendedInState = m_state;
204 alSourcePause(aldata->
source);
212 alSourcePlay(aldata->
source);
218 alGetSourcei(aldata->
source, AL_BUFFERS_PROCESSED, &processed);
219 return m_running ? m_bufferFragmentSize * (m_bufferFragmentsCount - m_bufferFragmentsBusyCount
228 m_bufferSize =
value;
239 alGetSourcei(aldata->
source, AL_BUFFERS_PROCESSED, &processed);
254 alGetSourcei(aldata->
source, AL_SOURCE_STATE, &
state);
276 m_bufferSize = m_bufferFragmentSize * m_bufferFragmentsCount;
277 m_tmpData =
new char[m_bufferFragmentSize];
299void QWasmAudioSink::loadALBuffers()
301 if (m_bufferFragmentsBusyCount == m_bufferFragmentsCount)
308 auto size = m_device->
read(m_tmpData + m_tmpDataOffset, m_bufferFragmentSize -
310 m_tmpDataOffset +=
size;
311 if (!m_tmpDataOffset || (m_tmpDataOffset != m_bufferFragmentSize &&
312 m_bufferFragmentsBusyCount >= m_bufferFragmentsCount * 2 / 3))
315 alBufferData(*aldata->
buffer, aldata->
format, m_tmpData, m_tmpDataOffset,
319 alSourceQueueBuffers(aldata->
source, 1, aldata->
buffer);
323 m_bufferFragmentsBusyCount++;
325 if (++aldata->
buffer == aldata->
buffers + m_bufferFragmentsCount)
329void QWasmAudioSink::unloadALBuffers()
332 alGetSourcei(aldata->
source, AL_BUFFERS_PROCESSED, &processed);
335 auto head = aldata->
buffer - m_bufferFragmentsBusyCount;
337 if (head + processed > aldata->
buffers) {
338 auto batch = m_bufferFragmentsBusyCount - (aldata->
buffer - aldata->
buffers);
340 alSourceUnqueueBuffers(aldata->
source, batch, head + m_bufferFragmentsCount);
342 m_bufferFragmentsBusyCount -= batch;
343 m_processed += m_bufferFragmentSize*batch;
350 head += m_bufferFragmentsCount;
354 alSourceUnqueueBuffers(aldata->
source, processed, head);
356 m_bufferFragmentsBusyCount -= processed;
360void QWasmAudioSink::nextALBuffers()
366 alGetSourcei(aldata->
source, AL_SOURCE_STATE, &
state);
368 alSourcePlay(aldata->
source);
372void QWasmAudioSink::updateState()
374 auto current =
state();
375 if (m_state == current)
388 if (
error == m_error)
393 alSourceRewind(aldata->
source);
416 alGetSourcei(m_out->aldata->
source, AL_SOURCE_STATE, &
state);
417 if (
state != AL_INITIAL)
418 m_out->unloadALBuffers();
419 if (m_out->m_bufferFragmentsBusyCount < m_out->m_bufferFragmentsCount) {
420 bool exceeds = m_out->m_tmpDataOffset +
len > m_out->m_bufferFragmentSize;
421 bool flush = m_out->m_bufferFragmentsBusyCount < m_out->m_bufferFragmentsCount * 2 / 3 ||
422 m_out->m_tmpDataOffset +
len >= m_out->m_bufferFragmentSize;
424 char *tmp = m_out->m_tmpData;
426 if (m_out->m_tmpDataOffset && exceeds) {
427 size = m_out->m_tmpDataOffset +
len;
428 tmp =
new char[m_out->m_tmpDataOffset +
len];
429 std::memcpy(tmp, m_out->m_tmpData, m_out->m_tmpDataOffset);
431 if (flush && !m_out->m_tmpDataOffset) {
435 std::memcpy(tmp + m_out->m_tmpDataOffset,
data,
len);
438 m_out->m_tmpDataOffset +=
len;
439 size = m_out->m_tmpDataOffset;
442 m_out->m_processed +=
size;
446 if (tmp && tmp != m_out->m_tmpData)
448 m_out->m_tmpDataOffset = 0;
450 alSourceQueueBuffers(m_out->aldata->
source, 1, m_out->aldata->
buffer);
453 m_out->m_bufferFragmentsBusyCount++;
454 if (++m_out->aldata->
buffer == m_out->aldata->
buffers + m_out->m_bufferFragmentsCount)
456 if (
state != AL_PLAYING)
457 alSourcePlay(m_out->aldata->
source);
IOBluetoothDevice * device
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
void invalidate() noexcept
Marks this QElapsedTimer object as invalid.
void start() noexcept
Starts this timer.
\inmodule QtCore \reentrant
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
QObject * parent() const
Returns a pointer to the parent object.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void deleteLater()
\threadsafe
void setSingleShot(bool singleShot)
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void setInterval(int msec)
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
qint64 readData(char *data, qint64 maxlen) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
qint64 writeData(const char *data, qint64 len) override
Writes up to maxSize bytes from data to the device.
QWasmAudioSinkDevice(QWasmAudioSink *parent)
qreal volume() const override
void setVolume(qreal volume) override
void setFormat(const QAudioFormat &fmt) override
QWasmAudioSink(const QByteArray &device, QObject *parent)
int bufferSize() const override
QIODevice * start() override
QAudio::State state() const override
QAudio::Error error() const override
friend class QWasmAudioSinkDevice
qint64 processedUSecs() const override
int bytesFree() const override
QAudioFormat format() const override
void setBufferSize(int value) override
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...
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr const T & qMax(const T &a, const T &b)
GLuint const GLuint * buffers
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
QVideoFrameFormat::PixelFormat fmt
#define AL_FORMAT_STEREO_FLOAT32
#define AL_FORMAT_MONO_FLOAT32
constexpr unsigned int DEFAULT_BUFFER_DURATION
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent