Ref T730, style and log messages

This commit is contained in:
Klaus Basan
2019-10-06 00:07:23 +02:00
committed by Mat Sutcliffe
parent e30b690191
commit 401c89aa63
10 changed files with 161 additions and 87 deletions

View File

@@ -37,6 +37,7 @@ int main(int argc, char *argv[])
CAfvClient *voiceClient = new CAfvClient("https://voice1.vatsim.uk", &qa); CAfvClient *voiceClient = new CAfvClient("https://voice1.vatsim.uk", &qa);
CAfvClientBridge *voiceClientBridge = new CAfvClientBridge(voiceClient, &qa); CAfvClientBridge *voiceClientBridge = new CAfvClientBridge(voiceClient, &qa);
voiceClient->start(QThread::TimeCriticalPriority); voiceClient->start(QThread::TimeCriticalPriority);
QObject::connect(&qa, &QCoreApplication::aboutToQuit, [voiceClient]() QObject::connect(&qa, &QCoreApplication::aboutToQuit, [voiceClient]()
@@ -48,7 +49,7 @@ int main(int argc, char *argv[])
QString defaultUserName("1234567"); QString defaultUserName("1234567");
if (CBuildConfig::isLocalDeveloperDebugBuild()) if (CBuildConfig::isLocalDeveloperDebugBuild())
{ {
CUser user("OBF:AwLZ7f9hUmpSZhm4=", "Joe Doe"); const CUser user("OBF:AwLZ7f9hUmpSZhm4=", "Joe Doe");
defaultUserName = user.getId(); defaultUserName = user.getId();
} }

View File

@@ -7,8 +7,11 @@
*/ */
#include "clientconnection.h" #include "clientconnection.h"
#include "blackmisc/logmessage.h"
#include <QNetworkDatagram> #include <QNetworkDatagram>
using namespace BlackMisc;
using namespace BlackCore::Afv::Crypto; using namespace BlackCore::Afv::Crypto;
namespace BlackCore namespace BlackCore
@@ -23,75 +26,64 @@ namespace BlackCore
m_voiceServerTimer(new QTimer(this)), m_voiceServerTimer(new QTimer(this)),
m_apiServerConnection(new CApiServerConnection(apiServer, this)) m_apiServerConnection(new CApiServerConnection(apiServer, this))
{ {
qDebug() << "ClientConnection instantiated"; CLogMessage(this).debug(u"ClientConnection instantiated");
// connect(&m_apiServerConnection, &ApiServerConnection::authenticationFinished, this, &ClientConnection::apiConnectionFinished); // connect(&m_apiServerConnection, &ApiServerConnection::authenticationFinished, this, &ClientConnection::apiConnectionFinished);
// connect(&m_apiServerConnection, &ApiServerConnection::addCallsignFinished, this, &ClientConnection::addCallsignFinished); // connect(&m_apiServerConnection, &ApiServerConnection::addCallsignFinished, this, &ClientConnection::addCallsignFinished);
// connect(&m_apiServerConnection, &ApiServerConnection::removeCallsignFinished, this, &ClientConnection::removeCallsignFinished); // connect(&m_apiServerConnection, &ApiServerConnection::removeCallsignFinished, this, &ClientConnection::removeCallsignFinished);
connect(m_voiceServerTimer, &QTimer::timeout, this, &CClientConnection::voiceServerHeartbeat); connect(m_voiceServerTimer, &QTimer::timeout, this, &CClientConnection::voiceServerHeartbeat);
connect(m_udpSocket, &QUdpSocket::readyRead, this, &CClientConnection::readPendingDatagrams); connect(m_udpSocket, &QUdpSocket::readyRead, this, &CClientConnection::readPendingDatagrams);
connect(m_udpSocket, qOverload<QAbstractSocket::SocketError>(&QUdpSocket::error), this, &CClientConnection::handleSocketError); connect(m_udpSocket, qOverload<QAbstractSocket::SocketError>(&QUdpSocket::error), this, &CClientConnection::handleSocketError);
} }
void CClientConnection::connectTo(const QString &userName, const QString &password, const QString &callsign) void CClientConnection::connectTo(const QString &userName, const QString &password, const QString &callsign)
{ {
if (m_connection.m_connected) if (m_connection.isConnected())
{ {
qDebug() << "Client already connected"; CLogMessage(this).debug(u"Client already connected");
return; return;
} }
m_connection.m_userName = userName; m_connection.setUserName(userName);
m_connection.m_callsign = callsign; m_connection.setCallsign(callsign);
bool result = m_apiServerConnection->connectTo(userName, password, m_networkVersion); bool result = m_apiServerConnection->connectTo(userName, password, m_networkVersion);
if (!result) { return; } if (!result) { return; }
m_connection.m_tokens = m_apiServerConnection->addCallsign(m_connection.m_callsign); m_connection.setTokens(m_apiServerConnection->addCallsign(m_connection.getCallsign()));
m_connection.m_authenticatedDateTimeUtc = QDateTime::currentDateTimeUtc(); m_connection.setTsAuthenticatedToNow();
m_connection.createCryptoChannels(); m_connection.createCryptoChannels();
connectToVoiceServer(); connectToVoiceServer();
// taskServerConnectionCheck.Start(); // taskServerConnectionCheck.Start();
m_connection.m_connected = true; m_connection.setConnected(true);
qDebug() << "Connected:" << callsign; CLogMessage(this).debug(u"Connected: '%1'") << callsign;
} }
void CClientConnection::disconnectFrom(const QString &reason) void CClientConnection::disconnectFrom(const QString &reason)
{ {
if (! m_connection.m_connected) if (!m_connection.isConnected())
{ {
qDebug() << "Client not connected"; CLogMessage(this).debug(u"Client not connected");
return; return;
} }
m_connection.m_connected = false; m_connection.setConnected(false);
// TODO emit disconnected(reason) // TODO emit disconnected(reason)
qDebug() << "Disconnected:" << reason; CLogMessage(this).debug(u"Disconnected client: %1") << reason;
if (! m_connection.m_callsign.isEmpty()) if (! m_connection.getCallsign().isEmpty())
{ {
m_apiServerConnection->removeCallsign(m_connection.m_callsign); m_apiServerConnection->removeCallsign(m_connection.getCallsign());
} }
// TODO connectionCheckCancelTokenSource.Cancel(); //Stops connection check loop // TODO connectionCheckCancelTokenSource.Cancel(); //Stops connection check loop
disconnectFromVoiceServer(); disconnectFromVoiceServer();
m_apiServerConnection->forceDisconnect(); m_apiServerConnection->forceDisconnect();
m_connection.m_tokens = {}; m_connection.setTokens({});
qDebug() << "Disconnection complete"; CLogMessage(this).debug(u"Disconnection complete");
}
bool CClientConnection::receiveAudioDto() const
{
return m_receiveAudioDto;
}
void CClientConnection::setReceiveAudioDto(bool receiveAudioDto)
{
m_receiveAudioDto = receiveAudioDto;
} }
void CClientConnection::updateTransceivers(const QString &callsign, const QVector<TransceiverDto> &transceivers) void CClientConnection::updateTransceivers(const QString &callsign, const QVector<TransceiverDto> &transceivers)
@@ -110,62 +102,62 @@ namespace BlackCore
m_udpSocket->bind(localAddress); m_udpSocket->bind(localAddress);
m_voiceServerTimer->start(3000); m_voiceServerTimer->start(3000);
qDebug() << "Connected to voice server (" + m_connection.m_tokens.VoiceServer.addressIpV4 << ")"; CLogMessage(this).info(u"Connected to voice server '%1'") << m_connection.getTokens().VoiceServer.addressIpV4;
} }
void CClientConnection::disconnectFromVoiceServer() void CClientConnection::disconnectFromVoiceServer()
{ {
m_voiceServerTimer->stop(); m_voiceServerTimer->stop();
m_udpSocket->disconnectFromHost(); m_udpSocket->disconnectFromHost();
qDebug() << "All TaskVoiceServer tasks stopped"; CLogMessage(this).info(u"All TaskVoiceServer tasks stopped");
} }
void CClientConnection::readPendingDatagrams() void CClientConnection::readPendingDatagrams()
{ {
while (m_udpSocket->hasPendingDatagrams()) while (m_udpSocket->hasPendingDatagrams())
{ {
QNetworkDatagram datagram = m_udpSocket->receiveDatagram(); const QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
processMessage(datagram.data()); this->processMessage(datagram.data());
} }
} }
void CClientConnection::processMessage(const QByteArray &messageDdata, bool loopback) void CClientConnection::processMessage(const QByteArray &messageDdata, bool loopback)
{ {
CryptoDtoSerializer::Deserializer deserializer = CryptoDtoSerializer::deserialize(*m_connection.voiceCryptoChannel, messageDdata, loopback); CryptoDtoSerializer::Deserializer deserializer = CryptoDtoSerializer::deserialize(*m_connection.m_voiceCryptoChannel, messageDdata, loopback);
if (deserializer.dtoNameBuffer == AudioRxOnTransceiversDto::getShortDtoName()) if (deserializer.dtoNameBuffer == AudioRxOnTransceiversDto::getShortDtoName())
{ {
// qDebug() << "Received audio data"; // qDebug() << "Received audio data";
AudioRxOnTransceiversDto audioOnTransceiverDto = deserializer.getDto<AudioRxOnTransceiversDto>(); const AudioRxOnTransceiversDto audioOnTransceiverDto = deserializer.getDto<AudioRxOnTransceiversDto>();
if (m_connection.m_receiveAudio && m_connection.m_connected) if (m_connection.isReceivingAudio() && m_connection.isConnected())
{ {
emit audioReceived(audioOnTransceiverDto); emit audioReceived(audioOnTransceiverDto);
} }
} }
else if (deserializer.dtoNameBuffer == HeartbeatAckDto::getShortDtoName()) else if (deserializer.dtoNameBuffer == HeartbeatAckDto::getShortDtoName())
{ {
m_connection.m_lastVoiceServerHeartbeatAckUtc = QDateTime::currentDateTimeUtc(); m_connection.setTsHeartbeatToNow();
qDebug() << "Received voice server heartbeat"; CLogMessage(this).debug(u"Received voice server heartbeat");
} }
else else
{ {
qWarning() << "Received unknown data:" << deserializer.dtoNameBuffer << deserializer.dataLength; CLogMessage(this).warning(u"Received unknown data: %1 %2") << QString(deserializer.dtoNameBuffer) << deserializer.dataLength;
} }
} }
void CClientConnection::handleSocketError(QAbstractSocket::SocketError error) void CClientConnection::handleSocketError(QAbstractSocket::SocketError error)
{ {
Q_UNUSED(error) Q_UNUSED(error)
qDebug() << "UDP socket error" << m_udpSocket->errorString(); CLogMessage(this).debug(u"UDP socket error: '%1'") << m_udpSocket->errorString();
} }
void CClientConnection::voiceServerHeartbeat() void CClientConnection::voiceServerHeartbeat()
{ {
const QUrl voiceServerUrl("udp://" + m_connection.m_tokens.VoiceServer.addressIpV4); const QUrl voiceServerUrl("udp://" + m_connection.getTokens().VoiceServer.addressIpV4);
qDebug() << "Sending voice server heartbeat to" << voiceServerUrl.host(); CLogMessage(this).debug(u"Sending voice server heartbeat to '%1'") << voiceServerUrl.host();
HeartbeatDto keepAlive; HeartbeatDto keepAlive;
keepAlive.callsign = m_connection.m_callsign.toStdString(); keepAlive.callsign = m_connection.getCallsign().toStdString();
const QByteArray dataBytes = CryptoDtoSerializer::serialize(*m_connection.voiceCryptoChannel, CryptoDtoMode::AEAD_ChaCha20Poly1305, keepAlive); const QByteArray dataBytes = CryptoDtoSerializer::serialize(*m_connection.m_voiceCryptoChannel, CryptoDtoMode::AEAD_ChaCha20Poly1305, keepAlive);
m_udpSocket->writeDatagram(dataBytes, QHostAddress(voiceServerUrl.host()), static_cast<quint16>(voiceServerUrl.port())); m_udpSocket->writeDatagram(dataBytes, QHostAddress(voiceServerUrl.host()), static_cast<quint16>(voiceServerUrl.port()));
} }
} // ns } // ns

View File

@@ -33,7 +33,7 @@ namespace BlackCore
Q_OBJECT Q_OBJECT
public: public:
//! Com status //! Connection status
enum ConnectionStatus enum ConnectionStatus
{ {
Disconnected, //!< Not connected Disconnected, //!< Not connected
@@ -41,32 +41,42 @@ namespace BlackCore
}; };
Q_ENUM(ConnectionStatus) Q_ENUM(ConnectionStatus)
//! Ctor
CClientConnection(const QString &apiServer, QObject *parent = nullptr); CClientConnection(const QString &apiServer, QObject *parent = nullptr);
//! Connect/disconnect @{
void connectTo(const QString &userName, const QString &password, const QString &callsign); void connectTo(const QString &userName, const QString &password, const QString &callsign);
void disconnectFrom(const QString &reason = {}); void disconnectFrom(const QString &reason = {});
bool isConnected() const { return m_connection.isConnected(); }
//! @}
bool isConnected() const { return m_connection.m_connected; } //! Receiving audio? @{
void setReceiveAudio(bool value) { m_connection.setReceiveAudio(value); }
void setReceiveAudio(bool value) { m_connection.m_receiveAudio = value; } bool receiveAudio() const { return m_connection.isReceivingAudio(); }
bool receiveAudio() const { return m_connection.m_receiveAudio; } bool receiveAudioDto() const { return m_receiveAudioDto; }
void setReceiveAudioDto(bool receiveAudioDto)
template<typename T>
void sendToVoiceServer(T dto)
{ {
QUrl voiceServerUrl("udp://" + m_connection.m_tokens.VoiceServer.addressIpV4); m_receiveAudioDto = receiveAudioDto;
QByteArray dataBytes = Crypto::CryptoDtoSerializer::serialize(*m_connection.voiceCryptoChannel, CryptoDtoMode::AEAD_ChaCha20Poly1305, dto); }
//! @}
//! Send voiceDTO to server
template<typename T>
void sendToVoiceServer(const T &dto)
{
const QUrl voiceServerUrl("udp://" + m_connection.getTokens().VoiceServer.addressIpV4);
const QByteArray dataBytes = Crypto::CryptoDtoSerializer::serialize(*m_connection.m_voiceCryptoChannel, Crypto::CryptoDtoMode::AEAD_ChaCha20Poly1305, dto);
m_udpSocket->writeDatagram(dataBytes, QHostAddress(voiceServerUrl.host()), static_cast<quint16>(voiceServerUrl.port())); m_udpSocket->writeDatagram(dataBytes, QHostAddress(voiceServerUrl.host()), static_cast<quint16>(voiceServerUrl.port()));
} }
bool receiveAudioDto() const; //! Update transceivers
void setReceiveAudioDto(bool receiveAudioDto);
void updateTransceivers(const QString &callsign, const QVector<TransceiverDto> &transceivers); void updateTransceivers(const QString &callsign, const QVector<TransceiverDto> &transceivers);
//! All aliased stations
QVector<StationDto> getAllAliasedStations(); QVector<StationDto> getAllAliasedStations();
signals: signals:
//! Audio has been received
void audioReceived(const AudioRxOnTransceiversDto &dto); void audioReceived(const AudioRxOnTransceiversDto &dto);
private: private:

View File

@@ -7,8 +7,10 @@
*/ */
#include "clientconnectiondata.h" #include "clientconnectiondata.h"
#include "blackmisc/logmessage.h"
#include <QDebug> #include <QDebug>
using namespace BlackMisc;
using namespace BlackCore::Afv::Crypto; using namespace BlackCore::Afv::Crypto;
namespace BlackCore namespace BlackCore
@@ -17,6 +19,12 @@ namespace BlackCore
{ {
namespace Connection namespace Connection
{ {
const CLogCategoryList &CClientConnectionData::getLogCategories()
{
static const CLogCategoryList cats { CLogCategory::audio(), CLogCategory::vatsimSpecific() };
return cats;
}
qint64 CClientConnectionData::secondsSinceAuthentication() const qint64 CClientConnectionData::secondsSinceAuthentication() const
{ {
return m_authenticatedDateTimeUtc.secsTo(QDateTime::currentDateTimeUtc()); return m_authenticatedDateTimeUtc.secsTo(QDateTime::currentDateTimeUtc());
@@ -31,15 +39,26 @@ namespace BlackCore
{ {
if (!m_tokens.isValid) if (!m_tokens.isValid)
{ {
qWarning() << "Tokens not set"; CLogMessage(this).warning(u"Tokens not set");
return;
} }
voiceCryptoChannel.reset(new CCryptoDtoChannel(m_tokens.VoiceServer.channelConfig)); m_voiceCryptoChannel.reset(new CCryptoDtoChannel(m_tokens.VoiceServer.channelConfig));
// dataCryptoChannel.reset(new CryptoDtoChannel(m_tokens.DataServer.channelConfig)); // dataCryptoChannel.reset(new CryptoDtoChannel(m_tokens.DataServer.channelConfig));
} }
void CClientConnectionData::setTsAuthenticatedToNow()
{
m_authenticatedDateTimeUtc = QDateTime::currentDateTimeUtc();
}
void CClientConnectionData::setTsHeartbeatToNow()
{
m_lastVoiceServerHeartbeatAckUtc = QDateTime::currentDateTimeUtc();
}
bool CClientConnectionData::voiceServerAlive() const bool CClientConnectionData::voiceServerAlive() const
{ {
return timeSinceAuthentication() < ServerTimeoutSecs || return timeSinceAuthenticationSecs() < ServerTimeoutSecs ||
m_lastVoiceServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) < ServerTimeoutSecs; m_lastVoiceServerHeartbeatAckUtc.secsTo(QDateTime::currentDateTimeUtc()) < ServerTimeoutSecs;
} }
} // ns } // ns

View File

@@ -13,6 +13,7 @@
#include "blackcore/afv/dto.h" #include "blackcore/afv/dto.h"
#include "apiserverconnection.h" #include "apiserverconnection.h"
#include "blackmisc/logcategorylist.h"
#include "blackcore/afv/crypto/cryptodtochannel.h" #include "blackcore/afv/crypto/cryptodtochannel.h"
#include <QDateTime> #include <QDateTime>
@@ -27,8 +28,12 @@ namespace BlackCore
namespace Connection namespace Connection
{ {
//! Client connection data //! Client connection data
struct CClientConnectionData class CClientConnectionData
{ {
public:
//! Categories
static const BlackMisc::CLogCategoryList &getLogCategories();
//! Ctor //! Ctor
CClientConnectionData() = default; CClientConnectionData() = default;
@@ -40,6 +45,39 @@ namespace BlackCore
bool isDataServerAlive() const; bool isDataServerAlive() const;
//! @} //! @}
//! Is connected? @{
bool isConnected() const { return m_connected; }
void setConnected(bool connected) { m_connected = connected; }
//! @}
//! Receiving audio? @{
bool isReceivingAudio() const { return m_receiveAudio; }
void setReceiveAudio(bool receive) { m_receiveAudio = receive; }
//! @}
//! Crypto channels for voice and data
void createCryptoChannels();
//! Tokens @{
const PostCallsignResponseDto &getTokens() const { return m_tokens; }
void setTokens(const PostCallsignResponseDto &dto) { m_tokens = dto; }
//! @}
//! Callsign @{
const QString &getCallsign() const { return m_callsign; }
void setCallsign(const QString &callsign) { m_callsign = callsign; }
//! @}
//! Uername @{
const QString &getUserName() const { return m_userName; }
void setUserName(const QString &un) { m_userName = un; }
//! @}
//! Timestamps @{
void setTsAuthenticatedToNow();
void setTsHeartbeatToNow();
//! @}
/* TODO /* TODO
public long VoiceServerBytesSent { get; set; } public long VoiceServerBytesSent { get; set; }
public long VoiceServerBytesReceived { get; set; } public long VoiceServerBytesReceived { get; set; }
@@ -47,17 +85,19 @@ namespace BlackCore
public long DataServerBytesReceived { get; set; } public long DataServerBytesReceived { get; set; }
*/ */
//! Crypto channels for voice and data QScopedPointer<Crypto::CCryptoDtoChannel> m_voiceCryptoChannel; //!< used crypto channel
void createCryptoChannels();
qint64 timeSinceAuthentication() const { return m_authenticatedDateTimeUtc.secsTo(QDateTime::currentDateTimeUtc()); } private:
//! Time since authentication
qint64 timeSinceAuthenticationSecs() const { return m_authenticatedDateTimeUtc.secsTo(QDateTime::currentDateTimeUtc()); }
//! Is the voice server alive?
bool voiceServerAlive() const; bool voiceServerAlive() const;
QString m_userName; //!< user name QString m_userName; //!< user name
QString m_callsign; //!< callsign QString m_callsign; //!< callsign
PostCallsignResponseDto m_tokens; //!< tokens PostCallsignResponseDto m_tokens; //!< tokens
QScopedPointer<Crypto::CCryptoDtoChannel> voiceCryptoChannel; //!< used crypto channel
QDateTime m_authenticatedDateTimeUtc; QDateTime m_authenticatedDateTimeUtc;
QDateTime m_lastVoiceServerHeartbeatAckUtc; QDateTime m_lastVoiceServerHeartbeatAckUtc;

View File

@@ -25,9 +25,9 @@ namespace BlackCore
//! DTO header //! DTO header
struct CryptoDtoHeaderDto struct CryptoDtoHeaderDto
{ {
std::string ChannelTag; std::string ChannelTag; //!< channel
uint64_t Sequence; uint64_t Sequence; //!< sequence
CryptoDtoMode Mode; CryptoDtoMode Mode; //!< mode
MSGPACK_DEFINE(ChannelTag, Sequence, Mode) MSGPACK_DEFINE(ChannelTag, Sequence, Mode)
}; };
} // ns } // ns

View File

@@ -13,14 +13,24 @@
#include "msgpack.hpp" #include "msgpack.hpp"
namespace BlackCore
{
namespace Afv
{
namespace Crypto
{
//! DTO mode //! DTO mode
enum class CryptoDtoMode enum class CryptoDtoMode
{ {
Undefined = 0, Undefined = 0, //!< undefined
None = 1, None = 1, //!< none
AEAD_ChaCha20Poly1305 = 2 AEAD_ChaCha20Poly1305 = 2 //!< AEAD
}; };
MSGPACK_ADD_ENUM(CryptoDtoMode); } // ns
} // ns
} // ns
MSGPACK_ADD_ENUM(BlackCore::Afv::Crypto::CryptoDtoMode);
#endif // guard #endif // guard

View File

@@ -283,7 +283,7 @@ namespace BlackCore
times.insert("Post setup, connects network", time.restart()); times.insert("Post setup, connects network", time.restart());
} }
// fake signals to work around setting values in audio context for local audio with remote core // connection status of network changed
if (m_contextAudio && m_contextAudio->isUsingImplementingObject()) if (m_contextAudio && m_contextAudio->isUsingImplementingObject())
{ {
Q_ASSERT(m_contextApplication); Q_ASSERT(m_contextApplication);

View File

@@ -8,11 +8,11 @@
//! \file //! \file
#ifndef BLACKSOUND_OPUSENCODER_H #ifndef BLACKSOUND_CODECS_OPUSENCODER_H
#define BLACKSOUND_OPUSENCODER_H #define BLACKSOUND_CODECS_OPUSENCODER_H
#include "blacksound/blacksoundexport.h"
#include "opus/opus.h" #include "opus/opus.h"
#include "blacksound/blacksoundexport.h"
#include <QByteArray> #include <QByteArray>
#include <QVector> #include <QVector>
@@ -31,18 +31,20 @@ namespace BlackSound
//! Dtor //! Dtor
~COpusEncoder(); ~COpusEncoder();
//! Bit rate
void setBitRate(int bitRate); void setBitRate(int bitRate);
//! \param frameCount Number of audio samples per frame //! \param frameCount Number of audio samples per frame
//! \returns the size of an audio frame in bytes //! \returns the size of an audio frame in bytes
int frameByteCount(int frameCount); int frameByteCount(int frameCount);
//! Frame count
int frameCount(const QVector<qint16> pcmSamples); int frameCount(const QVector<qint16> pcmSamples);
QByteArray encode(const QVector<qint16> pcmSamples, int samplesLength, int *encodedLength); QByteArray encode(const QVector<qint16> pcmSamples, int samplesLength, int *encodedLength);
private: private:
OpusEncoder *opusEncoder; OpusEncoder *opusEncoder = nullptr;
int m_sampleRate; int m_sampleRate;
int m_channels; int m_channels;

View File

@@ -15,7 +15,7 @@ namespace BlackSound
int CMixingSampleProvider::readSamples(QVector<float> &samples, qint64 count) int CMixingSampleProvider::readSamples(QVector<float> &samples, qint64 count)
{ {
samples.clear(); samples.clear();
samples.fill(0, count); samples.fill(0, static_cast<int>(count));
int outputLen = 0; int outputLen = 0;
QVector<ISampleProvider *> finishedProviders; QVector<ISampleProvider *> finishedProviders;
@@ -46,5 +46,5 @@ namespace BlackSound
return outputLen; return outputLen;
} }
} } // ns
} } // ns