aboutsummaryrefslogblamecommitdiff
path: root/src/plugins/Output/qtmultimedia/outputqtmultimedia.cpp
blob: 1f39ecc60a700b1d1b46b05175532f3f8f6af7c8 (plain) (tree)
























                                                                             

                    
                   

 
                                                                                          














                                                                                           



                                                                                             



                                         
                                     


                                          
                                     


                                          
                                     


                                          
                                     







                               

                                                                          













































                                                                                                                                      




                                                                                                                      






















                                                           
/***************************************************************************
 *   Copyright (C) 2015 by Ivan Ponomarev                                  *
 *   ivantrue@gmail.com                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "outputqtmultimedia.h"

#include <QAudioOutput>
#include <QAudioFormat>
#include <QAudioDeviceInfo>
#include <QSettings>
#include <QDebug>
#include <unistd.h>


OutputQtMultimedia::OutputQtMultimedia() : Output(), m_buffer(NULL), m_bytes_per_second(0)
{
}

OutputQtMultimedia::~OutputQtMultimedia()
{
}

bool OutputQtMultimedia::initialize(quint32 freq, ChannelMap map, Qmmp::AudioFormat format)
{
	QAudioFormat qformat;
	qformat.setCodec("audio/pcm");
	qformat.setFrequency(freq);
	qformat.setByteOrder(QAudioFormat::LittleEndian);
	qformat.setChannels(map.size());
	qformat.setSampleType(QAudioFormat::SignedInt);

	//Size of sample representation in input data. For 24-bit is 4, high byte is ignored.
	qint64 bytes_per_sample = 0;

	switch (format)
	{
	case Qmmp::PCM_S8:
		qformat.setSampleSize(8);
		bytes_per_sample = 1;
		break;
	case Qmmp::PCM_S16LE:
		qformat.setSampleSize(16);
		bytes_per_sample = 2;
		break;
	case Qmmp::PCM_S24LE:
		qformat.setSampleSize(24);
		bytes_per_sample = 4;
		break;
	case Qmmp::PCM_S32LE:
		qformat.setSampleSize(32);
		bytes_per_sample = 4;
		break;
	default:
		break;
	}

	if (!qformat.isValid())
		return false;

	m_bytes_per_second = bytes_per_sample * freq * qformat.channels();

	const QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
	const QString saved_device_name = settings.value("QTMULTIMEDIA/device").toString();

	QAudioDeviceInfo device_info;
	if (!saved_device_name.isEmpty())
	{
		const QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
		foreach (const QAudioDeviceInfo &info, devices)
		{
			if (info.deviceName()==saved_device_name)
			{
				if (info.isFormatSupported(qformat))
				{
					device_info = info;
					break;
				}
				else
					qDebug() << "OutputQtMultimedia: Output device: " << saved_device_name << " is not supported";
			}
		}
	}

	if (device_info.isNull())
	{
		device_info = QAudioDeviceInfo::defaultOutputDevice();
		if (!device_info.isFormatSupported(qformat))
			return false;
	}

	qDebug() << "OutputQtMultimedia: Using output device: " << device_info.deviceName();

	m_output.reset(new QAudioOutput(device_info, qformat));
	m_buffer = m_output->start();

	configure(freq, map, format);
	return true;
}


qint64 OutputQtMultimedia::latency()
{
	return 0;
}

qint64 OutputQtMultimedia::writeAudio(unsigned char *data, qint64 maxSize)
{
	if (!m_output->bytesFree()) {
		//If the buffer is full, waiting for some bytes to be played:
		//trying to play maxSize bytes, but not more than half of buffer.
		usleep(qMin(maxSize, static_cast<qint64>(m_output->bufferSize() / 2)) * 1000000 / m_bytes_per_second);
	}
	return m_buffer->write((const char*)data, maxSize);
}

void OutputQtMultimedia::drain()
{
	m_buffer->waitForBytesWritten(-1);
}

void OutputQtMultimedia::reset()
{
	m_buffer->reset();
	m_buffer = m_output->start();
}

void OutputQtMultimedia::suspend()
{
	m_output->suspend();
}

void OutputQtMultimedia::resume()
{
	m_output->resume();
}