Files
pilotclient/src/blackcore/afv/audio/input.cpp
2019-10-11 18:59:56 +01:00

174 lines
6.2 KiB
C++

/* Copyright (C) 2019
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
//! \file
#include "input.h"
#include "blacksound/audioutilities.h"
#include <QtGlobal>
#include <QDebug>
#include <cmath>
namespace BlackCore
{
namespace Afv
{
namespace Audio
{
CAudioInputBuffer::CAudioInputBuffer(QObject *parent) :
QIODevice(parent)
{}
void CAudioInputBuffer::start()
{
open(QIODevice::WriteOnly | QIODevice::Unbuffered);
m_timerId = startTimer(5, Qt::PreciseTimer);
}
void CAudioInputBuffer::stop()
{
if (m_timerId > 0)
{
killTimer(m_timerId);
m_timerId = 0;
}
close();
}
qint64 CAudioInputBuffer::readData(char *data, qint64 maxlen)
{
Q_UNUSED(data)
Q_UNUSED(maxlen)
return 0;
}
qint64 CAudioInputBuffer::writeData(const char *data, qint64 len)
{
// QByteArray buffer(data, static_cast<int>(len));
// m_buffer.append(buffer);
m_buffer.append(data, static_cast<int>(len));
qDebug() << QDateTime::currentMSecsSinceEpoch() << "[writeData] " << len << "buffer " << m_buffer.size();
return len;
}
void CAudioInputBuffer::timerEvent(QTimerEvent *event)
{
Q_UNUSED(event)
// 20 ms = 960 samples * 2 bytes = 1920 Bytes
if (m_buffer.size() < 1920) { return; }
const qint64 now = QDateTime::currentMSecsSinceEpoch();
const qint64 delta = now - m_lastFrameSent;
if (delta >= 19)
{
qDebug() << now << "[signal] frameAvailable - buffer size" << m_buffer.size();
m_buffer.remove(0, 1920);
m_lastFrameSent = now;
emit frameAvailable(m_buffer.left(1920));
}
}
CInput::CInput(int sampleRate, QObject *parent) :
QObject(parent),
m_sampleRate(sampleRate),
m_encoder(sampleRate, 1, OPUS_APPLICATION_VOIP)
{
m_encoder.setBitRate(16 * 1024);
}
void CInput::start(const QAudioDeviceInfo &inputDevice)
{
if (m_started) { return; }
QAudioFormat waveFormat;
waveFormat.setSampleRate(m_sampleRate);
waveFormat.setChannelCount(1);
waveFormat.setSampleSize(16);
waveFormat.setSampleType(QAudioFormat::SignedInt);
waveFormat.setByteOrder(QAudioFormat::LittleEndian);
waveFormat.setCodec("audio/pcm");
QAudioFormat inputFormat = waveFormat;
if (!inputDevice.isFormatSupported(inputFormat))
{
qWarning() << "Default format not supported - trying to use nearest";
inputFormat = inputDevice.nearestFormat(inputFormat);
}
m_audioInput.reset(new QAudioInput(inputDevice, inputFormat));
m_audioInputBuffer.start();
m_audioInput->start(&m_audioInputBuffer);
connect(&m_audioInputBuffer, &CAudioInputBuffer::frameAvailable, this, &CInput::audioInDataAvailable);
m_started = true;
}
void CInput::stop()
{
if (! m_started) { return; }
m_started = false;
m_audioInput->stop();
m_audioInput.reset();
}
void CInput::audioInDataAvailable(const QByteArray &frame)
{
QVector<qint16> samples = convertBytesTo16BitPCM(frame);
int value = 0;
for (qint16 &sample : samples)
{
value = qRound(sample * m_volume);
if (value > std::numeric_limits<qint16>::max())
value = std::numeric_limits<qint16>::max();
if (value < std::numeric_limits<qint16>::min())
value = std::numeric_limits<qint16>::min();
sample = static_cast<qint16>(value);
qint16 sampleInput = qAbs(sample);
m_maxSampleInput = qMax(qAbs(sampleInput), m_maxSampleInput);
}
int length;
QByteArray encodedBuffer = m_encoder.encode(samples, samples.size(), &length);
m_opusBytesEncoded += length;
m_sampleCount += samples.size();
if (m_sampleCount >= c_sampleCountPerEvent)
{
InputVolumeStreamArgs inputVolumeStreamArgs;
qint16 maxInt = std::numeric_limits<qint16>::max();
inputVolumeStreamArgs.PeakRaw = static_cast<float>(m_maxSampleInput) / maxInt;
inputVolumeStreamArgs.PeakDB = static_cast<float>(20 * std::log10(inputVolumeStreamArgs.PeakRaw));
float db = qBound(minDb, inputVolumeStreamArgs.PeakDB, maxDb);
float ratio = (db - minDb) / (maxDb - minDb);
if (ratio < 0.30)
ratio = 0;
if (ratio > 1.0)
ratio = 1;
inputVolumeStreamArgs.PeakVU = ratio;
emit inputVolumeStream(inputVolumeStreamArgs);
m_sampleCount = 0;
m_maxSampleInput = 0;
}
OpusDataAvailableArgs opusDataAvailableArgs = { m_audioSequenceCounter++, encodedBuffer };
emit opusDataAvailable(opusDataAvailableArgs);
}
} // ns
} // ns
} // ns