15#include <QtCore/qcoreapplication.h>
16#include <QtCore/qvarlengtharray.h>
17#include <QtMultimedia/private/qaudiohelpers_p.h>
20#include <QLoggingCategory>
64int QAlsaAudioSink::xrun_recovery(
int err)
78 err = snd_pcm_prepare(
handle);
82 }
else if ((err == -estrpipe)||(err == -EIO)) {
85 while((err = snd_pcm_resume(
handle)) == -EAGAIN){
94 err = snd_pcm_prepare(
handle);
110 snd_pcm_format_t pcmformat = SND_PCM_FORMAT_UNKNOWN;
114 pcmformat = SND_PCM_FORMAT_U8;
118 pcmformat = SND_PCM_FORMAT_S16_BE;
120 pcmformat = SND_PCM_FORMAT_S16_LE;
124 pcmformat = SND_PCM_FORMAT_S32_BE;
126 pcmformat = SND_PCM_FORMAT_S32_LE;
130 pcmformat = SND_PCM_FORMAT_FLOAT_BE;
132 pcmformat = SND_PCM_FORMAT_FLOAT_LE;
138 return pcmformat != SND_PCM_FORMAT_UNKNOWN
139 ? snd_pcm_hw_params_set_format(
handle, hwparams, pcmformat)
163 timer->start(period_time / 1000);
211bool QAlsaAudioSink::open()
220 elapsedTimeOffset = 0;
228 qWarning(
"QAudioSink: open error, invalid format.");
230 qWarning(
"QAudioSink: open error, invalid sample rate (%d).",
244 while((
count < 5) && (err < 0)) {
245 err=snd_pcm_open(&
handle, m_device.
constData(),SND_PCM_STREAM_PLAYBACK,0);
249 if (( err < 0)||(
handle == 0)) {
255 snd_pcm_nonblock(
handle, 0 );
258 snd_pcm_hw_params_alloca( &hwparams );
262 unsigned int chunks = 8;
264 err = snd_pcm_hw_params_any(
handle, hwparams );
270 err = snd_pcm_hw_params_set_rate_resample(
handle, hwparams, 1 );
273 errMessage =
QString::fromLatin1(
"QAudioSink: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err);
277 err = snd_pcm_hw_params_set_access(
handle, hwparams,
access );
280 errMessage =
QString::fromLatin1(
"QAudioSink: snd_pcm_hw_params_set_access: err = %1").arg(err);
287 errMessage =
QString::fromLatin1(
"QAudioSink: snd_pcm_hw_params_set_format: err = %1").arg(err);
294 errMessage =
QString::fromLatin1(
"QAudioSink: snd_pcm_hw_params_set_channels: err = %1").arg(err);
298 err = snd_pcm_hw_params_set_rate_near(
handle, hwparams, &sampleRate, 0 );
301 errMessage =
QString::fromLatin1(
"QAudioSink: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
305 unsigned int maxBufferTime = 0;
306 unsigned int minBufferTime = 0;
307 unsigned int maxPeriodTime = 0;
308 unsigned int minPeriodTime = 0;
310 err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &
dir);
312 err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &
dir);
314 err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &
dir);
316 err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &
dir);
320 errMessage =
QString::fromLatin1(
"QAudioSink: buffer/period min and max: err = %1").arg(err);
324 const bool outOfRange = maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time;
325 if (outOfRange || user_period_time || user_buffer_time) {
326 period_time = user_period_time ? user_period_time : minPeriodTime;
327 if (!user_buffer_time) {
328 chunks = maxBufferTime / period_time;
329 buffer_time = period_time * chunks;
331 buffer_time = user_buffer_time;
332 chunks = buffer_time / period_time;
335 qCDebug(lcAlsaOutput) <<
"buffer time: [" << minBufferTime <<
"-" << maxBufferTime <<
"] =" << buffer_time;
336 qCDebug(lcAlsaOutput) <<
"period time: [" << minPeriodTime <<
"-" << maxPeriodTime <<
"] =" << period_time;
337 qCDebug(lcAlsaOutput) <<
"chunks =" << chunks;
341 err = snd_pcm_hw_params_set_buffer_time_near(
handle, hwparams, &buffer_time, &
dir);
344 errMessage =
QString::fromLatin1(
"QAudioSink: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
348 err = snd_pcm_hw_params_set_period_time_near(
handle, hwparams, &period_time, &
dir);
351 errMessage =
QString::fromLatin1(
"QAudioSink: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err);
355 err = snd_pcm_hw_params_set_periods_near(
handle, hwparams, &chunks, &
dir);
358 errMessage =
QString::fromLatin1(
"QAudioSink: snd_pcm_hw_params_set_periods_near: err = %1").arg(err);
362 err = snd_pcm_hw_params(
handle, hwparams);
375 snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
376 buffer_size = snd_pcm_frames_to_bytes(
handle,buffer_frames);
377 snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &
dir);
378 period_size = snd_pcm_frames_to_bytes(
handle,period_frames);
379 snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &
dir);
380 snd_pcm_hw_params_get_period_time(hwparams,&period_time, &
dir);
383 snd_pcm_sw_params_t *swparams;
384 snd_pcm_sw_params_alloca(&swparams);
385 snd_pcm_sw_params_current(
handle, swparams);
386 snd_pcm_sw_params_set_start_threshold(
handle,swparams,period_frames);
387 snd_pcm_sw_params_set_stop_threshold(
handle,swparams,buffer_frames);
388 snd_pcm_sw_params_set_avail_min(
handle, swparams,period_frames);
389 snd_pcm_sw_params(
handle, swparams);
393 audioBuffer =
new char[snd_pcm_frames_to_bytes(
handle,buffer_frames)];
394 snd_pcm_prepare(
handle );
401 timer->
start(period_time/1000);
403 elapsedTimeOffset = 0;
411void QAlsaAudioSink::close()
419 delete [] audioBuffer;
437 int frames = snd_pcm_avail_update(
handle);
438 if (frames == -EPIPE) {
440 int err = snd_pcm_recover(
handle, frames, 0);
444 frames = snd_pcm_avail_update(
handle);
445 }
else if (frames < 0) {
449 if ((
int)frames > (
int)buffer_frames)
450 frames = buffer_frames;
452 return snd_pcm_frames_to_bytes(
handle, frames);
461 qDebug()<<
"frames to write out = "<<
462 snd_pcm_bytes_to_frames(
handle, (
int)
len )<<
" ("<<
len<<
") bytes";
473 frames = snd_pcm_bytes_to_frames(
handle, space);
475 if (m_volume < 1.0f) {
476 QVarLengthArray<char, 4096>
out(space);
478 err = snd_pcm_writei(
handle,
out.constData(), frames);
484 totalTimeValue += err;
491 return snd_pcm_frames_to_bytes(
handle, err );
493 err = xrun_recovery(err);
527 err = snd_pcm_prepare(
handle );
531 err = snd_pcm_start(
handle);
535 bytesAvailable = (int)snd_pcm_frames_to_bytes(
handle, buffer_frames);
541 timer->
start(period_time/1000);
568void QAlsaAudioSink::userFeed()
574 qDebug()<<
now.second()<<
"s "<<
now.msec()<<
"ms :userFeed() OUT";
582bool QAlsaAudioSink::deviceReady()
586 int chunks = bytesAvailable/period_size;
592 qDebug()<<
"deviceReady() avail="<<bytesAvailable<<
" bytes, period size="<<period_size<<
" bytes";
593 qDebug()<<
"deviceReady() no. of chunks that can fit ="<<chunks<<
", chunks in bytes ="<<period_size*chunks;
595 int input = period_frames*chunks;
596 if(
input > (
int)buffer_frames)
597 input = buffer_frames;
618 if(bytesAvailable > snd_pcm_frames_to_bytes(
handle, buffer_frames-period_frames)) {
637 if(bytesAvailable > snd_pcm_frames_to_bytes(
handle, buffer_frames-period_frames)) {
664 audioDevice = qobject_cast<QAlsaAudioSink*>(audio);
683 while(written <
len) {
684 int chunk = audioDevice->
write(
data+written,(
len-written));
698#include "moc_qalsaaudiosink_p.cpp"
IOBluetoothDevice * device
qint64 writeData(const char *data, qint64 len) override
Writes up to maxSize bytes from data to the device.
AlsaOutputPrivate(QAlsaAudioSink *audio)
qint64 readData(char *data, qint64 len) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
friend class AlsaOutputPrivate
QIODevice * start() override
void setBufferSize(qsizetype value) override
QAudio::State suspendedInState
qint64 processedUSecs() const override
void setFormat(const QAudioFormat &fmt) override
void setVolume(qreal) override
QAudio::State deviceState
QAudio::State state() const override
qreal volume() const override
qsizetype bytesFree() const override
QAudioFormat format() const override
qsizetype bufferSize() const override
QAudio::Error error() const override
qint64 write(const char *data, qint64 len)
void stateChanged(QAudio::State state)
void errorChanged(QAudio::Error error)
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
static void processEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Processes some pending events for the calling thread according to the specified flags.
\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 qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
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
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore \reentrant
static QTime currentTime()
Returns the current time as reported by the system clock.
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
bool isActive() const
Returns true if the timer is running (pending); otherwise returns false.
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void *src, void *dest, int len)
Combined button and popup list for selecting options.
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLenum GLsizei GLuint GLint * bytesWritten
GLuint64 GLenum void * handle
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLenum input
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
QVideoFrameFormat::PixelFormat fmt
QTextStream out(stdout)
[7]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
myObject disconnect()
[26]