19 #ifdef HAVE_QT_AUDIO_SUPPORT 25 #include <QApplication> 26 #include <QAudioDeviceInfo> 27 #include <QAudioFormat> 28 #include <QAudioOutput> 32 #include <KLocalizedString> 41 #define DEFAULT_DEVICE (i18n("Default device") + _("|sound_note")) 46 m_lock(QMutex::Recursive),
48 m_available_devices(),
70 switch (format.sampleType()) {
71 case QAudioFormat::SignedInt:
74 case QAudioFormat::UnSignedInt:
82 qWarning(
"PlayBackQt: unsupported sample format %d",
83 static_cast<int>(format.sampleType()));
87 unsigned int bits = 0;
88 switch (format.sampleSize()) {
89 case 8: bits = 8;
break;
90 case 16: bits = 16;
break;
91 case 24: bits = 24;
break;
92 case 32: bits = 32;
break;
93 default: bits = 0;
break;
96 qWarning(
"PlayBackQt: unsupported bits per sample: %d",
97 static_cast<int>(format.sampleSize()));
102 switch (format.byteOrder()) {
108 qWarning(
"PlayBackQt: unsupported byte order in audio format: %d",
109 static_cast<int>(format.byteOrder()));
119 unsigned int channels,
unsigned int bits,
120 unsigned int bufbase)
122 qDebug(
"PlayBackQt::open(device='%s', rate=%0.1f,channels=%u, bits=%u, " 123 "bufbase=%u)",
DBG(device), rate, channels, bits, bufbase);
125 if ((rate <
double(1.0f)) || !channels || !bits || !bufbase)
126 return i18n(
"One or more invalid/out of range arguments.");
131 QMutexLocker _lock(&
m_lock);
136 const QAudioDeviceInfo info(
deviceInfo(device));
138 return i18n(
"The audio device '%1' is unknown or no longer connected",
139 device.section(QLatin1Char(
'|'), 0, 0));
143 const QAudioFormat preferred_format(info.preferredFormat());
144 QAudioFormat format(preferred_format);
150 if (!format.isValid() || !info.isFormatSupported(format))
151 format = info.nearestFormat(format);
153 if (format.codec() !=
_(
"audio/pcm"))
154 return i18n(
"PCM encoding is not supported");
157 return i18n(
"%1 bits per sample are not supported", bits);
160 return i18n(
"playback with %1 channels is not supported", channels);
163 return i18n(
"sample rate %1 Hz is not supported",
Kwave::toInt(rate));
165 if ( (format.sampleType() != QAudioFormat::SignedInt) &&
166 (format.sampleType() != QAudioFormat::UnSignedInt) )
167 return i18n(
"integer sample format is not supported");
172 if (!
m_encoder)
return i18n(
"Out of memory");
175 m_output =
new QAudioOutput(format,
this);
177 if (!
m_output)
return i18n(
"Out of memory");
199 const int period_size =
m_output->periodSize();
200 qDebug(
" period_size = %d", period_size);
202 unsigned int buffer_size = qMax(qMax<int>(period_size,
m_buffer_size),
204 unsigned int buffer_frames =
205 ((buffer_size * 2) + (bytes_per_frame - 1)) / bytes_per_frame;
206 int timeout = qMax(
Kwave::toInt((1000 * buffer_frames) / rate), 100);
207 qDebug(
" timeout = %d ms", timeout);
210 if (
m_output->error() != QAudio::NoError) {
211 qDebug(
"error no: %d",
int(
m_output->error()));
212 return i18n(
"Opening the Qt Multimedia device '%1' failed", device);
224 QMutexLocker _lock(&
m_lock);
229 int bytes_raw = samples.
size() * bytes_per_sample;
231 frame.resize(bytes_raw);
237 if (written != frame.size()) {
238 qDebug(
"WARNING: Kwave::PlayBackQt::write: written=%lld/%d",
239 written, frame.size());
252 if (
m_output->error() != QAudio::NoError) {
253 qDebug(
"PlaybBackQt::stateChanged(%d), ERROR=%d, " 255 static_cast<int>(state),
256 static_cast<int>(
m_output->error()),
261 case QAudio::ActiveState:
262 qDebug(
"PlaybBackQt::stateChanged(ActiveState)");
264 case QAudio::SuspendedState:
265 qDebug(
"PlaybBackQt::stateChanged(SuspendedState)");
267 case QAudio::StoppedState: {
268 qDebug(
"PlaybBackQt::stateChanged(StoppedState)");
271 case QAudio::IdleState:
272 qDebug(
"PlaybBackQt::stateChanged(IdleState)");
275 qWarning(
"PlaybBackQt::stateChanged(%d)",
276 static_cast<int>(state));
286 return QAudioDeviceInfo::defaultOutputDevice();
290 return QAudioDeviceInfo();
296 if (dev.deviceName() == dev_name)
297 return QAudioDeviceInfo(dev);
301 return QAudioDeviceInfo();
307 qDebug(
"Kwave::PlayBackQt::close()");
309 QMutexLocker _lock(&
m_lock);
312 unsigned int pad_bytes_cnt =
m_output->periodSize();
313 unsigned int bytes_per_frame =
m_output->format().bytesPerFrame();
314 unsigned int pad_samples_cnt = pad_bytes_cnt / bytes_per_frame;
316 QByteArray pad_bytes(pad_bytes_cnt,
char(0));
322 qDebug(
"Kwave::PlayBackQt::close() - flushing..., state=%d",
326 (
m_output->state() == QAudio::ActiveState) &&
330 qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
333 qDebug(
"Kwave::PlayBackQt::close() - flushing done.");
349 qDebug(
"Kwave::PlayBackQt::close() - DONE");
356 QMutexLocker _lock(&
m_lock);
368 if (!list.isEmpty()) list.append(
_(
"#TREE#"));
380 foreach (
const QAudioDeviceInfo &device,
381 QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
383 QString qt_name = device.deviceName();
389 if (!qt_name.length()) {
390 qWarning(
"PlayBackQt::supportedDevices() " 391 "=> BUG: device with no name?");
395 QString gui_name = qt_name +
_(
"|sound_note");
397 qWarning(
"PlayBackQt::supportedDevices() " 398 "=> BUG: duplicate device name: '%s'",
DBG(gui_name));
416 QMutexLocker _lock(&
m_lock);
418 QList<unsigned int> list;
419 const QAudioDeviceInfo info(
deviceInfo(device));
422 if (info.isNull())
return list;
425 foreach (
int bits, info.supportedSampleSizes()) {
426 if (!list.contains(bits) && (bits > 0))
430 std::sort(list.begin(), list.end(), std::greater<unsigned int>());
436 unsigned int &min,
unsigned int &max)
438 QMutexLocker _lock(&
m_lock);
440 const QAudioDeviceInfo info(
deviceInfo(device));
442 max = std::numeric_limits<unsigned int>::min();
443 min = std::numeric_limits<unsigned int>::max();
446 if (info.isNull())
return -1;
449 foreach (
int channels, info.supportedChannelCounts()) {
450 if (channels <= 0)
continue;
453 if (c < min) min = c;
454 if (c > max) max = c;
457 return (max > 0) ? max : -1;
466 m_lock(QMutex::Recursive),
492 open(QIODevice::ReadOnly);
498 QMutexLocker _lock(&
m_lock);
500 qDebug(
"Kwave::PlayBackQt::Buffer::setTimeout(%d)", timeout);
519 qint64 read_bytes = -1;
520 qint64 requested = len;
523 if (len == 0)
return 0;
524 if (len < 0)
return -1;
527 int count = qMin<int>(
533 QMutexLocker _lock(&
m_lock);
536 if (read_bytes < 0) read_bytes = 0;
545 while ( (read_bytes < requested) &&
553 if (read_bytes != requested)
554 qDebug(
"Kwave::PlayBackQt::Buffer::readData(...) -> read=%lld/%lld",
555 read_bytes, requested);
564 qint64 written_bytes = 0;
566 int count = qMin<int>(
571 QMutexLocker _lock(&
m_lock);
573 written_bytes += count;
580 return written_bytes;
586 return QIODevice::bytesAvailable() +
virtual QList< unsigned int > supportedBits(const QString &device) Q_DECL_OVERRIDE
virtual unsigned int rawBytesPerSample()=0
QList< QAudioDeviceInfo > m_available_devices
Kwave::SampleEncoder * m_encoder
virtual qint64 bytesAvailable() const Q_DECL_OVERRIDE
virtual qint64 readData(char *data, qint64 len) Q_DECL_OVERRIDE
virtual int detectChannels(const QString &device, unsigned int &min, unsigned int &max) Q_DECL_OVERRIDE
virtual QString fileFilter() Q_DECL_OVERRIDE
void stateChanged(QAudio::State state)
QMap< QString, QString > m_device_name_map
QAudioDeviceInfo deviceInfo(const QString &device) const
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
void start(unsigned int buf_size, int timeout)
virtual qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE
virtual int close() Q_DECL_OVERRIDE
void createEncoder(const QAudioFormat &format)
virtual QStringList supportedDevices() Q_DECL_OVERRIDE
virtual int write(const Kwave::SampleArray &samples) Q_DECL_OVERRIDE
void setTimeout(int timeout)
Kwave::PlayBackQt::Buffer m_buffer
unsigned int size() const
unsigned int m_buffer_size
virtual ~PlayBackQt() Q_DECL_OVERRIDE
virtual ~Buffer() Q_DECL_OVERRIDE
virtual QString open(const QString &device, double rate, unsigned int channels, unsigned int bits, unsigned int bufbase) Q_DECL_OVERRIDE
QQueue< char > m_raw_buffer
virtual void encode(const Kwave::SampleArray &samples, unsigned int count, QByteArray &raw_data)=0
void drain(QByteArray &padding)