mirror of
https://github.com/QuasarApp/SoundBand.git
synced 2025-04-26 07:14:31 +00:00
commit
7b6e435460
@ -34,7 +34,9 @@ SOURCES += main.cpp \
|
||||
serverlistmodel.cpp \
|
||||
playlistsmodel.cpp \
|
||||
currentplaylistmodel.cpp \
|
||||
../sync/playlist.cpp
|
||||
../sync/playlist.cpp \
|
||||
../sync/syncpackage.cpp \
|
||||
../sync/basepackage.cpp
|
||||
|
||||
|
||||
RESOURCES += qml.qrc
|
||||
@ -71,5 +73,7 @@ HEADERS += \
|
||||
serverlistmodel.h \
|
||||
playlistsmodel.h \
|
||||
currentplaylistmodel.h \
|
||||
../sync/playlist.h
|
||||
../sync/playlist.h \
|
||||
../sync/syncpackage.h \
|
||||
../sync/basepackage.h
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "currentplaylistmodel.h"
|
||||
|
||||
using namespace syncLib;
|
||||
|
||||
CurrentPlayListModel::CurrentPlayListModel(QObject *parent) :
|
||||
QAbstractListModel(parent),
|
||||
syncEngine(nullptr),
|
||||
@ -47,13 +45,13 @@ void CurrentPlayListModel::fetchMore(const QModelIndex & /* index */)
|
||||
int remainder = playList->size() - itemCount;
|
||||
int itemsToFetch = qMin(100, remainder);
|
||||
|
||||
if(itemsToFetch < 0){
|
||||
if (itemsToFetch < 0) {
|
||||
beginRemoveRows(QModelIndex(), 0, 0 - itemsToFetch - 1 );
|
||||
|
||||
itemCount += itemsToFetch;
|
||||
|
||||
endRemoveRows();
|
||||
}else{
|
||||
} else if (itemsToFetch > 0) {
|
||||
beginInsertRows(QModelIndex(), itemCount, itemCount + itemsToFetch - 1);
|
||||
|
||||
itemCount += itemsToFetch;
|
||||
@ -78,10 +76,8 @@ QVariant CurrentPlayListModel::data(const QModelIndex &index, int role) const
|
||||
switch (role) {
|
||||
case nameRole:
|
||||
return playList->at(index.row()).name;
|
||||
break;
|
||||
case idRole:
|
||||
return playList->at(index.row()).id;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class CurrentPlayListModel : public QAbstractListModel
|
||||
|
||||
private:
|
||||
SyncEngine * syncEngine;
|
||||
const QList<syncLib::SongStorage> *playList;
|
||||
const QList<SongStorage> *playList;
|
||||
int itemCount;
|
||||
|
||||
private slots:
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "playlistmodel.h"
|
||||
|
||||
using namespace syncLib;
|
||||
|
||||
PlayListModel::PlayListModel(QObject *parent) :
|
||||
QAbstractListModel(parent),
|
||||
syncEngine(nullptr)
|
||||
@ -55,7 +53,7 @@ void PlayListModel::fetchMore(const QModelIndex & /* index */)
|
||||
itemCount += itemsToFetch;
|
||||
|
||||
endRemoveRows();
|
||||
}else{
|
||||
}else if (itemsToFetch > 0){
|
||||
beginInsertRows(QModelIndex(), itemCount, itemCount + itemsToFetch - 1);
|
||||
|
||||
itemCount += itemsToFetch;
|
||||
@ -94,7 +92,7 @@ QVariant PlayListModel::data(const QModelIndex &index, int role) const
|
||||
|
||||
bool PlayListModel::select(int id){
|
||||
|
||||
for(QList<syncLib::SongStorage>::Iterator i = playList.begin(); i < playList.end(); i++){
|
||||
for(QList<SongStorage>::Iterator i = playList.begin(); i < playList.end(); i++){
|
||||
if(i->id == id){
|
||||
|
||||
if((i->isSelected = !i->isSelected)){
|
||||
@ -114,7 +112,7 @@ bool PlayListModel::select(int id){
|
||||
QList<int> PlayListModel::getSelected(){
|
||||
QList<int> result;
|
||||
|
||||
for(QList<syncLib::SongStorage>::Iterator i = playList.begin(); i < playList.end(); i++){
|
||||
for(QList<SongStorage>::Iterator i = playList.begin(); i < playList.end(); i++){
|
||||
if(i->isSelected){
|
||||
result.push_back(i->id);
|
||||
}
|
||||
@ -124,7 +122,7 @@ QList<int> PlayListModel::getSelected(){
|
||||
|
||||
bool PlayListModel::isSelected(int id){
|
||||
|
||||
for(QList<syncLib::SongStorage>::Iterator i = playList.begin(); i < playList.end(); i++){
|
||||
for(QList<SongStorage>::Iterator i = playList.begin(); i < playList.end(); i++){
|
||||
if(i->id == id){
|
||||
return i->isSelected;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class PlayListModel : public QAbstractListModel
|
||||
|
||||
private:
|
||||
SyncEngine * syncEngine;
|
||||
QList<syncLib::SongStorage> playList;
|
||||
QList<SongStorage> playList;
|
||||
QString playListName;
|
||||
int itemCount;
|
||||
|
||||
|
@ -42,13 +42,13 @@ void PlayListsModel::fetchMore(const QModelIndex & /* index */)
|
||||
int remainder = playLists.size() - itemCount;
|
||||
int itemsToFetch = qMin(100, remainder);
|
||||
|
||||
if(itemsToFetch < 0){
|
||||
if (itemsToFetch < 0) {
|
||||
beginRemoveRows(QModelIndex(), 0, 0 - itemsToFetch - 1 );
|
||||
|
||||
itemCount += itemsToFetch;
|
||||
|
||||
endRemoveRows();
|
||||
}else{
|
||||
} else if (itemsToFetch > 0) {
|
||||
beginInsertRows(QModelIndex(), itemCount, itemCount + itemsToFetch - 1);
|
||||
|
||||
itemCount += itemsToFetch;
|
||||
|
@ -41,13 +41,13 @@ void ServerListModel::fetchMore(const QModelIndex & /* index */)
|
||||
int remainder = servers->size() - itemCount;
|
||||
int itemsToFetch = qMin(100, remainder);
|
||||
|
||||
if(itemsToFetch < 0){
|
||||
if (itemsToFetch < 0) {
|
||||
beginRemoveRows(QModelIndex(), 0, 0 - itemsToFetch - 1 );
|
||||
|
||||
itemCount += itemsToFetch;
|
||||
|
||||
endRemoveRows();
|
||||
}else{
|
||||
} else if (itemsToFetch > 0) {
|
||||
beginInsertRows(QModelIndex(), itemCount, itemCount + itemsToFetch - 1);
|
||||
|
||||
itemCount += itemsToFetch;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
SyncEngine::SyncEngine()
|
||||
{
|
||||
sync = new syncLib::Sync();
|
||||
sync = new Sync();
|
||||
sqlApi = sync->getSqlApi();
|
||||
|
||||
connect(sync, SIGNAL(networkStateChange()), this, SIGNAL(serversCountChanged()));
|
||||
@ -44,7 +44,7 @@ bool SyncEngine::init(){
|
||||
return true;
|
||||
}
|
||||
|
||||
const QList<syncLib::SongStorage>* SyncEngine::currentPlayList() const{
|
||||
const QList<SongStorage>* SyncEngine::currentPlayList() const{
|
||||
|
||||
return sync->getPlayList();
|
||||
}
|
||||
@ -196,7 +196,7 @@ bool SyncEngine::addSong(const QString &songUrl){
|
||||
}
|
||||
|
||||
bool SyncEngine::removeSong(int id){
|
||||
syncLib::SongHeader header;
|
||||
SongHeader header;
|
||||
header.id = id;
|
||||
if(!sqlApi->removeSong(header))
|
||||
return false;
|
||||
@ -223,7 +223,7 @@ bool SyncEngine::removePlayList(const QString &name){
|
||||
|
||||
bool SyncEngine::addToPlayList(int id, const QString &playList){
|
||||
|
||||
syncLib::SongHeader header;
|
||||
SongHeader header;
|
||||
header.id = id;
|
||||
|
||||
if(!sqlApi->addToPlayList(header, playList)){
|
||||
@ -239,7 +239,7 @@ bool SyncEngine::addToPlayList(int id, const QString &playList){
|
||||
|
||||
bool SyncEngine::removeFromPlayList(int id, const QString &playList){
|
||||
|
||||
syncLib::SongHeader header;
|
||||
SongHeader header;
|
||||
header.id = id;
|
||||
|
||||
if(!sqlApi->removeFromPlayList(header, playList)){
|
||||
|
@ -20,8 +20,8 @@ class SyncEngine : public QObject
|
||||
|
||||
|
||||
private:
|
||||
syncLib::Sync *sync;
|
||||
syncLib::MySql * sqlApi;
|
||||
Sync *sync;
|
||||
MySql * sqlApi;
|
||||
QString _lastError;
|
||||
QSettings settings;
|
||||
|
||||
|
@ -13,7 +13,7 @@ ETcpSocket::ETcpSocket(QTcpSocket*ptr)
|
||||
init();
|
||||
}
|
||||
|
||||
ETcpSocket::ETcpSocket(const QString& address, int port){
|
||||
ETcpSocket::ETcpSocket(const QString& address, unsigned short port){
|
||||
source = new QTcpSocket();
|
||||
source->connectToHost(address, port);
|
||||
if(!source->waitForConnected(DEEP_SCANER_INTERVAL) || !source->open(QIODevice::ReadWrite)){
|
||||
@ -24,14 +24,134 @@ ETcpSocket::ETcpSocket(const QString& address, int port){
|
||||
|
||||
void ETcpSocket::init(){
|
||||
array = new QByteArray;
|
||||
time = 0;
|
||||
fSynced = false;
|
||||
|
||||
connect(source,SIGNAL(connected()),this,SLOT(connected_()));
|
||||
connect(source,SIGNAL(disconnected()),this,SLOT(disconnected_()));
|
||||
connect(source,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(error_(QAbstractSocket::SocketError)));
|
||||
connect(source,SIGNAL(hostFound()),this,SLOT(hostFound_()));
|
||||
connect(source,SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),this,SLOT(proxyAuthenticationRequired_(const QNetworkProxy &, QAuthenticator *)));
|
||||
connect(source,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(stateChanged_(QAbstractSocket::SocketState)));
|
||||
connect(source,SIGNAL(readyRead()),this,SLOT(readReady_()));
|
||||
connect(source, SIGNAL(connected()), this, SLOT(connected_()));
|
||||
connect(source, SIGNAL(disconnected()), this, SLOT(disconnected_()));
|
||||
connect(source, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||
this, SLOT(error_(QAbstractSocket::SocketError)));
|
||||
connect(source, SIGNAL(hostFound()), this,SLOT(hostFound_()));
|
||||
connect(source,
|
||||
SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
|
||||
this, SLOT(proxyAuthenticationRequired_(const QNetworkProxy &, QAuthenticator *)));
|
||||
connect(source, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
|
||||
this ,SLOT(stateChanged_(QAbstractSocket::SocketState)));
|
||||
connect(source, SIGNAL(readyRead()), this, SLOT(readReady_()));
|
||||
}
|
||||
|
||||
bool ETcpSocket::_driverResponse(const SyncPackage& from) {
|
||||
|
||||
if(!from.isValid()){
|
||||
return false;
|
||||
}
|
||||
|
||||
SyncPackage pac;
|
||||
|
||||
switch (from.type) {
|
||||
case t_Header:
|
||||
syncList.clear();
|
||||
precisionSync = from.getPrecision();
|
||||
lastTime = ChronoTime::now();
|
||||
pac.sourceBytes = ChronoTime::now();
|
||||
pac.nativeTime = from.getTime();
|
||||
pac.type = t_Source;
|
||||
pac.firstByte = 0;
|
||||
|
||||
_Write(pac.parseTo(), true);
|
||||
|
||||
syncList[0] = pac;
|
||||
|
||||
|
||||
break;
|
||||
case t_Source:
|
||||
syncList[from.getIndex()] = from;
|
||||
pac.type = t_Responce;
|
||||
pac.firstByte = from.getIndex();
|
||||
pac.sourceBytes = ChronoTime::now();
|
||||
|
||||
_Write(pac.parseTo(), true);
|
||||
break;
|
||||
case t_Responce:
|
||||
syncList[from.getIndex()].ping = ChronoTime::now() - lastTime;
|
||||
lastTime = ChronoTime::now();
|
||||
|
||||
if(syncList.size() >= precisionSync){
|
||||
pac.type = t_End;
|
||||
|
||||
auto ping = syncList.first().ping;
|
||||
auto index = syncList.begin();
|
||||
for (auto i = syncList.begin(); i != syncList.end(); i++) {
|
||||
if (i.value().ping < ping) {
|
||||
ping = i.value().ping;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
pac.firstByte = index->firstByte;
|
||||
pac.sourceBytes = index->ping;
|
||||
pac.nativeTime = index->nativeTime;
|
||||
|
||||
_Write(pac.parseTo(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
pac.type = t_Source;
|
||||
pac.firstByte = from.getIndex() + 1;
|
||||
pac.sourceBytes = ChronoTime::now();
|
||||
pac.nativeTime = from.getTime();
|
||||
|
||||
_Write(pac.parseTo(), true);
|
||||
|
||||
syncList[pac.firstByte] = pac;
|
||||
|
||||
break;
|
||||
case t_End: {
|
||||
|
||||
if(syncList.size() <= from.getIndex()){
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ping = from.getPing();
|
||||
|
||||
if (ping > 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time = from.getNative() - syncList[from.getIndex()].getTime() - from.getPing() / 2;
|
||||
fSynced = true;
|
||||
qDebug() << "syncTime :" << time;
|
||||
|
||||
emit synced();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ETcpSocket::_driverStart() {
|
||||
syncList.clear();
|
||||
|
||||
SyncPackage pac;
|
||||
|
||||
precisionSync = SYNC_COUNT;
|
||||
pac.type = t_Header;
|
||||
pac.firstByte = precisionSync;
|
||||
pac.sourceBytes = ChronoTime::now();
|
||||
|
||||
_Write(pac.parseTo(), true);
|
||||
}
|
||||
|
||||
void ETcpSocket::_driver(QByteArray *data){
|
||||
SyncPackage pac;
|
||||
if(!pac.parseFrom(*data)){
|
||||
return;
|
||||
}
|
||||
_driverResponse(pac);
|
||||
}
|
||||
|
||||
void ETcpSocket::error_(QAbstractSocket::SocketError i){
|
||||
@ -70,9 +190,16 @@ void ETcpSocket::readReady_(){
|
||||
qDebug()<<"messae size:" << size;
|
||||
qDebug()<<"message package size:" << array->size();
|
||||
#endif
|
||||
if(size==array->size())
|
||||
if(size == array->size())
|
||||
{
|
||||
array->remove(0, sizeof(qint32));
|
||||
if(array->back()){
|
||||
_driver(array);
|
||||
delete array;
|
||||
array = new QByteArray();
|
||||
return;
|
||||
}
|
||||
array->remove(array->size() - 1, 1);
|
||||
ReadyStack.push_back(array);
|
||||
array=new QByteArray();
|
||||
emit Message(this);
|
||||
@ -97,13 +224,31 @@ QString ETcpSocket::localName() const{
|
||||
QByteArray* ETcpSocket::topStack(){
|
||||
if(ReadyStack.size())
|
||||
return ReadyStack.front();
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
milliseconds ETcpSocket::getTime()const{
|
||||
return time;
|
||||
}
|
||||
|
||||
QTcpSocket* ETcpSocket::getSource()const{
|
||||
return source;
|
||||
}
|
||||
|
||||
void ETcpSocket::sync(){
|
||||
if(fSynced){
|
||||
return;
|
||||
}
|
||||
_driverStart();
|
||||
|
||||
}
|
||||
|
||||
bool ETcpSocket::isSynced()const{
|
||||
return fSynced;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ETcpSocket::nextItem(bool free){
|
||||
if( ReadyStack.size()){
|
||||
if(free){
|
||||
@ -122,13 +267,18 @@ QString ETcpSocket::toStringTcp(){
|
||||
return source->peerAddress().toString();
|
||||
}
|
||||
|
||||
bool ETcpSocket::Write(const QByteArray&data){
|
||||
bool ETcpSocket::Write(const QByteArray &data){
|
||||
return _Write(data);
|
||||
}
|
||||
|
||||
bool ETcpSocket::_Write(const QByteArray&data, bool isDriver){
|
||||
if(source->state()==QTcpSocket::ConnectedState){
|
||||
QByteArray array;
|
||||
QDataStream stream(&array, QIODevice::ReadWrite);
|
||||
|
||||
stream << qint32(0);
|
||||
array.append(data);
|
||||
array.append(qint8(isDriver));
|
||||
stream.device()->seek(0);
|
||||
stream<<qint32(array.size());
|
||||
|
||||
@ -144,12 +294,19 @@ bool ETcpSocket::Write(const QByteArray&data){
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ETcpSocket::isValid(){
|
||||
return source->isValid() && source->isOpen();
|
||||
}
|
||||
|
||||
ETcpSocket::~ETcpSocket()
|
||||
{
|
||||
for(QByteArray*i:ReadyStack){
|
||||
i->clear();
|
||||
delete i;
|
||||
}
|
||||
|
||||
syncList.clear();
|
||||
|
||||
disconnect(source,SIGNAL(connected()),this,SLOT(connected_()));
|
||||
disconnect(source,SIGNAL(disconnected()),this,SLOT(disconnected_()));
|
||||
disconnect(source,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(error_(QAbstractSocket::SocketError)));
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <QTcpServer>
|
||||
#include <QList>
|
||||
#include <QDataStream>
|
||||
#include "chronotime.h"
|
||||
#include "syncpackage.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -36,9 +36,41 @@ private:
|
||||
QTcpSocket *source;
|
||||
QByteArray *array;
|
||||
qint32 size;
|
||||
milliseconds time;
|
||||
milliseconds lastTime;
|
||||
char precisionSync;
|
||||
QList<QByteArray*> ReadyStack;
|
||||
bool fSynced;
|
||||
QMap<char ,SyncPackage> syncList;
|
||||
void init();
|
||||
|
||||
/**
|
||||
* @brief _driverResponse
|
||||
* @param pac
|
||||
* @return true if all done
|
||||
*/
|
||||
bool _driverResponse(const SyncPackage &from);
|
||||
|
||||
/**
|
||||
* @brief _driverResponse
|
||||
* @param pac
|
||||
* @return true if all done
|
||||
*/
|
||||
void _driverStart();
|
||||
|
||||
/**
|
||||
* @brief _driver
|
||||
* @return true is package of Driver
|
||||
*/
|
||||
void _driver(QByteArray*);
|
||||
|
||||
/**
|
||||
* @brief Write - sends a message to the network.
|
||||
* @param isDriver - flag of driver info
|
||||
* @return true if all done else false.
|
||||
*/
|
||||
bool _Write(const QByteArray&, bool isDriver = false);
|
||||
|
||||
private slots:
|
||||
|
||||
void connected_();
|
||||
@ -51,7 +83,18 @@ private slots:
|
||||
public:
|
||||
explicit ETcpSocket();
|
||||
explicit ETcpSocket(QTcpSocket*);
|
||||
explicit ETcpSocket(const QString& addres,int port);
|
||||
explicit ETcpSocket(const QString& addres, unsigned short port);
|
||||
|
||||
/**
|
||||
* @brief sync
|
||||
*/
|
||||
void sync();
|
||||
|
||||
/**
|
||||
* @brief isSynced
|
||||
* @return true
|
||||
*/
|
||||
bool isSynced()const;
|
||||
|
||||
/**
|
||||
* @brief setCheckInterval - set new interval of chking ping
|
||||
@ -66,10 +109,15 @@ public:
|
||||
int getCheckInterval()const;
|
||||
|
||||
/**
|
||||
* @brief getPing
|
||||
* @return ping of soccket;
|
||||
* @brief setTime set new Time
|
||||
*/
|
||||
int getPing()const;
|
||||
void setTime(milliseconds newTime);
|
||||
|
||||
/**
|
||||
* @brief getTime
|
||||
* @return time of soccket;
|
||||
*/
|
||||
milliseconds getTime()const;
|
||||
/**
|
||||
* @brief getSource
|
||||
* @return Qt TCP socket
|
||||
@ -92,6 +140,13 @@ public:
|
||||
* @return size of Descript of Packege
|
||||
*/
|
||||
int sizeDescriptPackege();
|
||||
|
||||
/**
|
||||
* @brief isValid
|
||||
* @return true if socket active;
|
||||
*/
|
||||
bool isValid();
|
||||
|
||||
/**
|
||||
* @brief Write - sends a message to the network.
|
||||
* @return true if all done else false.
|
||||
@ -163,6 +218,12 @@ signals:
|
||||
void StateChanged(ETcpSocket*,QAbstractSocket::SocketState socketState);
|
||||
|
||||
|
||||
/**
|
||||
* @brief synced emited when host is synced
|
||||
*/
|
||||
void synced();
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // CLIENT_H
|
||||
|
118
sync/basepackage.cpp
Normal file
118
sync/basepackage.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
#include "basepackage.h"
|
||||
|
||||
package::package()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
package::package( QByteArray &array):
|
||||
package::package(){
|
||||
parseFrom(array);
|
||||
}
|
||||
|
||||
const SongHeader& package::getHeader() const{
|
||||
return header;
|
||||
}
|
||||
|
||||
const Song& package::getSong() const{
|
||||
return source;
|
||||
}
|
||||
|
||||
const Syncer& package::getPlayData() const{
|
||||
return playdata;
|
||||
}
|
||||
|
||||
const Type& package::getType() const{
|
||||
return type;
|
||||
}
|
||||
|
||||
bool package::isValid() const{
|
||||
|
||||
bool ret = true;
|
||||
if(type == TypePackage::t_void){
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_sync && type & t_brodcaster){
|
||||
ret = ret && playdata.seek > 0 && playdata.timeOn > 0;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h && type & t_brodcaster){
|
||||
ret = ret && header.size > 0;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song && type & t_brodcaster){
|
||||
ret = ret && source.size > 0;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void package::clear(){
|
||||
type = TypePackage::t_void;
|
||||
source.clear();
|
||||
playdata.seek = 0;
|
||||
}
|
||||
|
||||
QByteArray package::parseTo(){
|
||||
QByteArray temp;
|
||||
QDataStream stream(&temp, QIODevice::WriteOnly);
|
||||
temp.clear();
|
||||
if(isValid()){
|
||||
stream << static_cast<unsigned char>(type);
|
||||
|
||||
if(type & TypePackage::t_sync && type & t_brodcaster){
|
||||
stream << playdata.seek;
|
||||
stream << playdata.timeOn;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h && type & t_brodcaster){
|
||||
stream << header;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song && type & t_brodcaster){
|
||||
stream << source;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool package::parseFrom(QByteArray &array){
|
||||
type = TypePackage::t_void;
|
||||
QDataStream stream(&array, QIODevice::ReadOnly);
|
||||
|
||||
unsigned char temp_type;
|
||||
stream >> temp_type;
|
||||
type = static_cast<TypePackage> (temp_type);
|
||||
|
||||
if(type & TypePackage::t_sync){
|
||||
stream >> playdata.seek;
|
||||
stream >> playdata.timeOn;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h){
|
||||
stream >> header;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song){
|
||||
stream >> source;
|
||||
|
||||
}
|
||||
|
||||
return isValid();
|
||||
}
|
||||
|
||||
package::~package(){}
|
||||
|
112
sync/basepackage.h
Normal file
112
sync/basepackage.h
Normal file
@ -0,0 +1,112 @@
|
||||
#ifndef BASEPACKAGE_H
|
||||
#define BASEPACKAGE_H
|
||||
|
||||
#include "song.h"
|
||||
#include "config.h"
|
||||
#include <QByteArray>
|
||||
|
||||
typedef unsigned char Type;
|
||||
|
||||
/**
|
||||
* @brief The TypePackage enum
|
||||
* t_void = this package empty and not valid.
|
||||
* t_play = play current audio file.
|
||||
* t_song_h = the header of playing audio file.
|
||||
* t_song = the package with this type is necessary for translite media data on network.
|
||||
* t_sync = the infomation about sync playning media file on network.
|
||||
* t_close = the information about close channel.
|
||||
* t_syncTime = getLocalTime of socket
|
||||
* t_what = request for information about the node
|
||||
* t_brodcaster = information about the node
|
||||
*/
|
||||
|
||||
enum TypePackage{
|
||||
t_void = 0x00,
|
||||
t_play = 0x01,
|
||||
t_song_h = 0x02,
|
||||
t_song = 0x04,
|
||||
t_sync = 0x08,
|
||||
t_close = 0x10,
|
||||
t_pause = 0x20,
|
||||
t_what = 0x40,
|
||||
t_brodcaster = 0x80
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The package class. Package for translite media data on network
|
||||
*
|
||||
* parse map:
|
||||
* 1 byle - type
|
||||
* data
|
||||
*/
|
||||
class package
|
||||
{
|
||||
|
||||
private:
|
||||
Type type;
|
||||
Song source;
|
||||
SongHeader header;
|
||||
bool fbroadcaster;
|
||||
Syncer playdata;
|
||||
public:
|
||||
package();
|
||||
package(QByteArray &array);
|
||||
~package();
|
||||
|
||||
/**
|
||||
* @brief getHeader
|
||||
* @return Header of the song
|
||||
*/
|
||||
const SongHeader& getHeader() const;
|
||||
|
||||
/**
|
||||
* @brief getSong
|
||||
* @return Song
|
||||
*/
|
||||
const Song& getSong() const;
|
||||
|
||||
/**
|
||||
* @brief getPlayTime
|
||||
* @return time of playning media data
|
||||
*/
|
||||
const Syncer &getPlayData() const;
|
||||
|
||||
/**
|
||||
* @brief getType
|
||||
* @return type of package
|
||||
*/
|
||||
const Type& getType() const;
|
||||
|
||||
/**
|
||||
* @brief getTime
|
||||
* @return time of sended package pc
|
||||
*/
|
||||
const milliseconds& getTime()const;
|
||||
|
||||
/**
|
||||
* @brief isValid
|
||||
* @return true if package is valid
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @brief clear all date of package
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @brief parseTo parse this package to byte array
|
||||
* @return byte array
|
||||
*/
|
||||
QByteArray parseTo();
|
||||
|
||||
/**
|
||||
* @brief parseFrom create a package from bytes
|
||||
* @param array of bytes
|
||||
* @return true if package valid
|
||||
*/
|
||||
bool parseFrom(QByteArray& array);
|
||||
friend class Sync;
|
||||
};
|
||||
|
||||
#endif // BASEPACKAGE_H
|
@ -1,24 +1,32 @@
|
||||
#include "chronotime.h"
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
ChronoTime::ChronoTime()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* information about chrono
|
||||
* https://stackoverflow.com/questions/31255486/c-how-do-i-convert-a-stdchronotime-point-to-long-and-back
|
||||
*/
|
||||
|
||||
milliseconds ChronoTime::now(int calibration){
|
||||
milliseconds ChronoTime::stdTime() {
|
||||
auto tim = std::chrono::system_clock::now();
|
||||
auto mc = std::chrono::time_point_cast<std::chrono::milliseconds>(tim);
|
||||
auto epoh = mc.time_since_epoch();
|
||||
#ifdef QT_DEBUG
|
||||
qDebug() << epoh.count();
|
||||
#endif
|
||||
return epoh.count() + calibration;
|
||||
return epoh.count();
|
||||
}
|
||||
|
||||
milliseconds ChronoTime::qtTime() {
|
||||
return QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
ChronoTime::ChronoTime()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
milliseconds ChronoTime::now(milliseconds calibration){
|
||||
return qtTime() + calibration;
|
||||
}
|
||||
|
||||
Clock ChronoTime::from(const milliseconds& mc){
|
||||
|
@ -11,13 +11,16 @@ typedef std::chrono::time_point<std::chrono::high_resolution_clock> Clock;
|
||||
|
||||
class ChronoTime
|
||||
{
|
||||
private :
|
||||
static milliseconds stdTime();
|
||||
static milliseconds qtTime();
|
||||
public:
|
||||
ChronoTime();
|
||||
/**
|
||||
* @brief now - get now time on microsecunds
|
||||
* @return - count of microsecunds
|
||||
*/
|
||||
static milliseconds now(int calibration = 0);
|
||||
static milliseconds now(milliseconds calibration = 0);
|
||||
/**
|
||||
* @brief from cast to chrono secunds
|
||||
* @param mcrs microseconds of uint_64
|
||||
|
@ -25,8 +25,8 @@
|
||||
#define RESYNC_TIME 1000 // 1 sec on millisec
|
||||
#define MAX_RESYNC_COUNT 3
|
||||
#define SYNC_TIME 5 * 1000 // 5 sec on millisec
|
||||
#define SYNC_COUNT 20
|
||||
#define DEEP_SCANER_INTERVAL 1000 // 1 sec
|
||||
#define CHECK_PING_INTERVAL 5 * 60 *1000// 5 minutes
|
||||
|
||||
// sync
|
||||
#define MIN_DIFFERENCE 10 // millisec
|
||||
|
@ -5,8 +5,6 @@
|
||||
#include <QSettings>
|
||||
#include "playlist.h"
|
||||
|
||||
namespace syncLib{
|
||||
|
||||
MySql::MySql(const QString &databasename):
|
||||
db(nullptr),
|
||||
qyery(nullptr)
|
||||
@ -119,43 +117,7 @@ void MySql::initDB(const QString &database){
|
||||
}
|
||||
}
|
||||
|
||||
bool MySql::find(const QMediaContent &song, SongStorage &response){
|
||||
QList<SongStorage> songs;
|
||||
|
||||
if(!updateAvailableSongs(songs)){
|
||||
return false;
|
||||
}
|
||||
|
||||
for(SongStorage &i: songs){
|
||||
if(i == song){
|
||||
response = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool MySql::find(const QMediaContent &song, SongHeader &response){
|
||||
QList<SongStorage> songs;
|
||||
|
||||
if(!updateAvailableSongs(songs)){
|
||||
return false;
|
||||
}
|
||||
|
||||
for(SongStorage &i: songs){
|
||||
if(i == song){
|
||||
response = (SongHeader&)i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool MySql::find(const SongHeader &song, QMediaContent &response){
|
||||
bool MySql::find(const SongHeader &song, SongStorage &response){
|
||||
QList<SongStorage> songs;
|
||||
|
||||
if(!updateAvailableSongs(songs)){
|
||||
@ -164,7 +126,7 @@ bool MySql::find(const SongHeader &song, QMediaContent &response){
|
||||
|
||||
for(SongStorage &i: songs){
|
||||
if((SongHeader&)i == song){
|
||||
response = i.toMedia();
|
||||
response = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -182,6 +144,9 @@ bool MySql::saveToStorage(QUrl &url, const Song &song) const{
|
||||
return false;
|
||||
}
|
||||
|
||||
QDir dir;
|
||||
dir.mkpath(songDir);
|
||||
|
||||
QFile file(songDir + "/" + song.name);
|
||||
|
||||
if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
|
||||
@ -510,5 +475,5 @@ MySql::~MySql(){
|
||||
QSqlDatabase::removeDatabase(dataBaseName);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
21
sync/mysql.h
21
sync/mysql.h
@ -6,8 +6,6 @@
|
||||
class QSqlDatabase;
|
||||
class QSqlQuery;
|
||||
|
||||
namespace syncLib {
|
||||
|
||||
class MySql
|
||||
{
|
||||
private:
|
||||
@ -43,23 +41,7 @@ public:
|
||||
* @param response Media Content of finded song
|
||||
* @return true if song finded
|
||||
*/
|
||||
bool find(const SongHeader& song, QMediaContent& response);
|
||||
|
||||
/**
|
||||
* @brief find - find song
|
||||
* @param song - song header
|
||||
* @param response Media Content of finded song
|
||||
* @return true if song finded
|
||||
*/
|
||||
bool find(const QMediaContent& song, SongHeader& response);
|
||||
|
||||
/**
|
||||
* @brief find - find song
|
||||
* @param song - media Content
|
||||
* @param response header of finded song
|
||||
* @return true if song finded
|
||||
*/
|
||||
bool find(const QMediaContent& song, SongStorage &response);
|
||||
bool find(const SongHeader& song, SongStorage &response);
|
||||
|
||||
/**
|
||||
* @brief setSoundDir
|
||||
@ -194,5 +176,4 @@ public:
|
||||
|
||||
~MySql();
|
||||
};
|
||||
}
|
||||
#endif // MYSQL_H
|
||||
|
137
sync/node.cpp
137
sync/node.cpp
@ -2,123 +2,10 @@
|
||||
#include "exaptions.h"
|
||||
#include "LocalScanner.h"
|
||||
|
||||
namespace syncLib{
|
||||
|
||||
package::package()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
package::package( QByteArray &array):
|
||||
package::package(){
|
||||
parseFrom(array);
|
||||
}
|
||||
|
||||
const SongHeader& package::getHeader() const{
|
||||
return header;
|
||||
}
|
||||
|
||||
const Song& package::getSong() const{
|
||||
return source;
|
||||
}
|
||||
|
||||
const Syncer& package::getPlayData() const{
|
||||
return playdata;
|
||||
}
|
||||
|
||||
const Type& package::getType() const{
|
||||
return type;
|
||||
}
|
||||
|
||||
bool package::isValid() const{
|
||||
|
||||
bool ret = true;
|
||||
if(type == TypePackage::t_void){
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_sync && type & t_brodcaster){
|
||||
ret = ret && (playdata.seek > 0);
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h && type & t_brodcaster){
|
||||
ret = ret && header.size > 0;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song && type & t_brodcaster){
|
||||
ret = ret && source.size > 0;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void package::clear(){
|
||||
type = TypePackage::t_void;
|
||||
source.clear();
|
||||
playdata.seek = 0;
|
||||
}
|
||||
|
||||
QByteArray package::parseTo(){
|
||||
QByteArray temp;
|
||||
QDataStream stream(&temp, QIODevice::WriteOnly);
|
||||
temp.clear();
|
||||
if(isValid()){
|
||||
stream << static_cast<unsigned char>(type);
|
||||
|
||||
if(type & TypePackage::t_sync && type & t_brodcaster){
|
||||
stream << playdata.seek;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h && type & t_brodcaster){
|
||||
stream << header;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song && type & t_brodcaster){
|
||||
stream << source;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool package::parseFrom(QByteArray &array){
|
||||
type = TypePackage::t_void;
|
||||
QDataStream stream(&array, QIODevice::ReadOnly);
|
||||
|
||||
unsigned char temp_type;
|
||||
stream >> temp_type;
|
||||
type = static_cast<TypePackage> (temp_type);
|
||||
|
||||
if(type & TypePackage::t_sync){
|
||||
stream >> playdata.seek;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h){
|
||||
stream >> header;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song){
|
||||
stream >> source;
|
||||
|
||||
}
|
||||
|
||||
return isValid();
|
||||
}
|
||||
|
||||
package::~package(){}
|
||||
|
||||
Node::Node(const QString &addres, int port):QTcpServer(){
|
||||
QString address = addres;
|
||||
fBroadcaster = false;
|
||||
if(address == DEFAULT_ADRESS){
|
||||
address = LocalScanner::thisAddress().toString();
|
||||
}
|
||||
@ -132,7 +19,9 @@ Node::Node(const QString &addres, int port):QTcpServer(){
|
||||
#ifdef QT_DEBUG
|
||||
qDebug() << "node started on:" << serverAddress().toString() << "port:" << serverPort();
|
||||
#endif
|
||||
|
||||
connect(this,SIGNAL(newConnection()),SLOT(newConnection_()));
|
||||
|
||||
}
|
||||
|
||||
void Node::acceptError_(ETcpSocket*c){
|
||||
@ -145,6 +34,14 @@ void Node::acceptError_(ETcpSocket*c){
|
||||
delete c;
|
||||
}
|
||||
|
||||
bool Node::isBroadcaster()const{
|
||||
return fBroadcaster;
|
||||
}
|
||||
|
||||
void Node::setBroadcaster(bool newValue){
|
||||
fBroadcaster = newValue;
|
||||
}
|
||||
|
||||
QList<ETcpSocket*>* Node::getClients(){
|
||||
return &clients;
|
||||
}
|
||||
@ -152,11 +49,18 @@ QList<ETcpSocket*>* Node::getClients(){
|
||||
void Node::newConnection_(){
|
||||
ETcpSocket *newClient=new ETcpSocket(nextPendingConnection());
|
||||
clients.push_back(newClient);
|
||||
connect(newClient,SIGNAL(Disconnected(ETcpSocket*)),this,SLOT(acceptError_(ETcpSocket*)));
|
||||
connect(newClient,SIGNAL(Message(ETcpSocket*)),this,SLOT(readData(ETcpSocket*)));
|
||||
connect(newClient, SIGNAL(Disconnected(ETcpSocket*)),
|
||||
this, SLOT(acceptError_(ETcpSocket*)));
|
||||
connect(newClient, SIGNAL(Message(ETcpSocket*)), this, SLOT(readData(ETcpSocket*)));
|
||||
connect(newClient, SIGNAL(synced()), this, SLOT(synced()));
|
||||
|
||||
emit ClientConnected(newClient);
|
||||
}
|
||||
|
||||
void Node::synced(){
|
||||
emit NodeSynced(static_cast<ETcpSocket*>(this->sender()));
|
||||
}
|
||||
|
||||
void Node::readData(ETcpSocket *c){
|
||||
emit Message(c);
|
||||
}
|
||||
@ -211,6 +115,5 @@ Node::~Node(){
|
||||
this->close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
141
sync/node.h
141
sync/node.h
@ -2,104 +2,101 @@
|
||||
#define NODE_H
|
||||
#include <QTcpServer>
|
||||
#include "ETcpSocket.h"
|
||||
#include "song.h"
|
||||
#include "config.h"
|
||||
|
||||
namespace syncLib {
|
||||
|
||||
typedef unsigned char Type;
|
||||
#include <QTimer>
|
||||
#include "basepackage.h"
|
||||
#include "syncpackage.h"
|
||||
|
||||
/**
|
||||
* @brief The TypePackage enum
|
||||
* t_void = this package empty and not valid.
|
||||
* t_play = play current audio file.
|
||||
* t_song_h = the header of playing audio file.
|
||||
* t_song = the package with this type is necessary for translite media data on network.
|
||||
* t_sync = the infomation about sync playning media file on network.
|
||||
* t_close = the information about close channel.
|
||||
* t_stop = the package with type 'stop' necessary for stoping playning media files.
|
||||
* t_what = request for information about the node
|
||||
* t_brodcaster = information about the node
|
||||
*/
|
||||
|
||||
enum TypePackage{
|
||||
t_void = 0x00,
|
||||
t_play = 0x01,
|
||||
t_song_h = 0x02,
|
||||
t_song = 0x04,
|
||||
t_sync = 0x08,
|
||||
t_close = 0x10,
|
||||
t_stop = 0x20,
|
||||
t_what = 0x40,
|
||||
t_brodcaster = 0x80
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The package class. Package for translite media data on network
|
||||
*
|
||||
* parse map:
|
||||
* 1 byle - type
|
||||
* data
|
||||
* @brief The Node class is tcp server class
|
||||
*/
|
||||
class package
|
||||
{
|
||||
|
||||
private:
|
||||
Type type;
|
||||
Song source;
|
||||
SongHeader header;
|
||||
Syncer playdata;
|
||||
public:
|
||||
package();
|
||||
package(QByteArray &array);
|
||||
~package();
|
||||
/**
|
||||
* @brief getHeader
|
||||
* @return Header of the song
|
||||
*/
|
||||
const SongHeader& getHeader() const;
|
||||
/**
|
||||
* @brief getSong
|
||||
* @return Song
|
||||
*/
|
||||
const Song& getSong() const;
|
||||
/**
|
||||
* @brief getPlayTime
|
||||
* @return time of playning media data
|
||||
*/
|
||||
const Syncer &getPlayData() const;
|
||||
const Type& getType() const;
|
||||
bool isValid() const;
|
||||
void clear();
|
||||
QByteArray parseTo();
|
||||
bool parseFrom(QByteArray& array);
|
||||
friend class Sync;
|
||||
};
|
||||
|
||||
class Node:public QTcpServer{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QTimer *timer;
|
||||
int index;
|
||||
protected:
|
||||
QList<ETcpSocket*> clients;
|
||||
bool fBroadcaster;
|
||||
int step;
|
||||
private slots:
|
||||
void synced();
|
||||
void acceptError_(ETcpSocket*);
|
||||
void newConnection_();
|
||||
void readData(ETcpSocket*_client);
|
||||
public:
|
||||
Node(const QString &addres = DEFAULT_ADRESS, int port = DEFAULT_PORT);
|
||||
|
||||
/**
|
||||
* @brief isBroadcaster
|
||||
* @return true if this node is server
|
||||
*/
|
||||
bool isBroadcaster()const;
|
||||
|
||||
/**
|
||||
* @brief setBroadcaster set new state for this node
|
||||
*/
|
||||
void setBroadcaster(bool newValue);
|
||||
|
||||
/**
|
||||
* @brief WriteAll send package to all connected clients
|
||||
*/
|
||||
void WriteAll(const QByteArray&);
|
||||
|
||||
/**
|
||||
* @brief disconnectClient disconet a client
|
||||
*/
|
||||
void disconnectClient(ETcpSocket*);
|
||||
|
||||
/**
|
||||
* @brief getClients
|
||||
* @return list of all connected clients
|
||||
*/
|
||||
QList<ETcpSocket*>* getClients();
|
||||
|
||||
/**
|
||||
* @brief addNode add new client for network
|
||||
* @param node if of node
|
||||
* @param port port of node
|
||||
* @return true if all done
|
||||
*/
|
||||
bool addNode(const QString &node, int port);
|
||||
|
||||
/**
|
||||
* @brief addNode a connected node
|
||||
* @param node tcp socket
|
||||
* @return true if all done
|
||||
*/
|
||||
bool addNode(ETcpSocket* node);
|
||||
|
||||
~Node();
|
||||
signals:
|
||||
/**
|
||||
* @brief Error signal when a error detected
|
||||
*/
|
||||
void Error(QString);
|
||||
|
||||
/**
|
||||
* @brief Message signal when accepted a mewssage from other node
|
||||
*/
|
||||
void Message(ETcpSocket*);
|
||||
|
||||
/**
|
||||
* @brief ClientDisconnected - signal when node disconected from this node
|
||||
*/
|
||||
void ClientDisconnected(ETcpSocket*);
|
||||
|
||||
/**
|
||||
* @brief ClientConnected signal when connected a new node
|
||||
*/
|
||||
void ClientConnected(ETcpSocket*);
|
||||
|
||||
/**
|
||||
* @brief NodeSynced emited when socket synced
|
||||
*/
|
||||
void NodeSynced(ETcpSocket*);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // NODE_H
|
||||
|
@ -3,8 +3,6 @@
|
||||
#include <QMediaPlaylist>
|
||||
#include "song.h"
|
||||
|
||||
using namespace syncLib;
|
||||
|
||||
/**
|
||||
* @brief The PlayList class
|
||||
* palyList with songs info
|
||||
|
@ -3,8 +3,6 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QFile>
|
||||
|
||||
namespace syncLib{
|
||||
|
||||
static const QStringList ValidSongs = {".mp3", ".wav", ".ogg"};
|
||||
SongHeader::SongHeader()
|
||||
{
|
||||
@ -161,8 +159,8 @@ QMediaContent SongStorage::toMedia()const{
|
||||
return QMediaContent(url);
|
||||
}
|
||||
|
||||
bool SongStorage::toSong(Song&)const{
|
||||
Song song(*((SongHeader*)this));
|
||||
bool SongStorage::toSong(Song& song)const{
|
||||
song = (*((SongHeader*)this));
|
||||
|
||||
QFile f(url.toLocalFile());
|
||||
|
||||
@ -230,4 +228,3 @@ QDataStream& operator >> (QDataStream& stream, Song& song){
|
||||
return stream;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,6 @@
|
||||
#include "chronotime.h"
|
||||
#include <QMediaContent>
|
||||
|
||||
namespace syncLib {
|
||||
|
||||
/**
|
||||
* @brief The Syncer struct
|
||||
*
|
||||
@ -18,6 +16,11 @@ struct Syncer
|
||||
* @brief seek - wher is play media file
|
||||
*/
|
||||
milliseconds seek;
|
||||
|
||||
/**
|
||||
* @brief timeOn - when play this media file
|
||||
*/
|
||||
milliseconds timeOn;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -97,5 +100,4 @@ public:
|
||||
friend class MySql;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // SONG_H
|
||||
|
214
sync/sync.cpp
214
sync/sync.cpp
@ -10,8 +10,6 @@
|
||||
#include <QDebug>
|
||||
#endif
|
||||
|
||||
namespace syncLib{
|
||||
|
||||
Sync::Sync(const QString &address, int port, const QString &datadir):
|
||||
node(nullptr),
|
||||
player(nullptr)
|
||||
@ -26,27 +24,25 @@ Sync::Sync(const QString &address, int port, const QString &datadir):
|
||||
|
||||
player->setPlaylist(playList->getList());
|
||||
|
||||
|
||||
fbroadcaster = false;
|
||||
resyncCount = 0;
|
||||
lastSyncTime = 0;
|
||||
ping = 0;
|
||||
|
||||
sql = new MySql(datadir);
|
||||
|
||||
connect(node, SIGNAL(Message(ETcpSocket*)), SLOT(packageRender(ETcpSocket*)));
|
||||
connect(&deepScaner, SIGNAL(scaned(QList<ETcpSocket*>*)), SLOT(deepScaned(QList<ETcpSocket*>*)));
|
||||
connect(player, SIGNAL(positionChanged(qint64)), SIGNAL(seekChanged(qint64)));
|
||||
connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(endPlay(QMediaPlayer::State)));
|
||||
connect(node, SIGNAL(NodeSynced(ETcpSocket*)), SLOT(clientSynced(ETcpSocket*)));
|
||||
|
||||
}
|
||||
|
||||
MySql* Sync::getSqlApi(){
|
||||
return sql;
|
||||
}
|
||||
|
||||
bool Sync::setSingle(const QMediaContent& media){
|
||||
bool Sync::setSingle(const SongStorage& media){
|
||||
playList->clear();
|
||||
playList->addMedia(media);
|
||||
if(!playList->addMedia(media)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
emit currentPlayListChanged();
|
||||
return true;
|
||||
@ -71,9 +67,9 @@ const QString& Sync::getPlayListName() const{
|
||||
}
|
||||
|
||||
bool Sync::play(bool fbroadcast){
|
||||
fbroadcaster = fbroadcast;
|
||||
node->setBroadcaster(fbroadcast);
|
||||
|
||||
if(fbroadcaster){
|
||||
if(fbroadcast){
|
||||
player->play();
|
||||
sync();
|
||||
}else{
|
||||
@ -95,7 +91,9 @@ bool Sync::play(const SongStorage &song, bool fbroadcast){
|
||||
}
|
||||
|
||||
playList->clear();
|
||||
playList->addMedia(song);
|
||||
if(!playList->addMedia(song)){
|
||||
return false;
|
||||
}
|
||||
|
||||
return play(fbroadcast);
|
||||
}
|
||||
@ -126,9 +124,9 @@ bool Sync::play(const Song &song, bool fbroadcast){
|
||||
return false;
|
||||
}
|
||||
|
||||
QMediaContent savedSong;
|
||||
SongStorage savedSong;
|
||||
if(!sql->find(static_cast<const SongHeader&>(song), savedSong) && sql->save(song) > -1 &&
|
||||
!sql->find((SongHeader&)song, savedSong)){
|
||||
!sql->find(static_cast<const SongHeader&>(song), savedSong)){
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -136,19 +134,6 @@ bool Sync::play(const Song &song, bool fbroadcast){
|
||||
return play(savedSong, fbroadcast);
|
||||
}
|
||||
|
||||
bool Sync::play(const QMediaContent& media, bool fbroadcast){
|
||||
|
||||
if(media.isNull()){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!setSingle(media)){
|
||||
return false;
|
||||
}
|
||||
|
||||
return Sync::play(fbroadcast);
|
||||
}
|
||||
|
||||
bool Sync::play(int id_song, bool fbroadcast){
|
||||
|
||||
if(id_song < 0){
|
||||
@ -209,40 +194,62 @@ void Sync::stop(){
|
||||
|
||||
void Sync::jump(const qint64 seek){
|
||||
player->setPosition(seek);
|
||||
sync();
|
||||
|
||||
}
|
||||
|
||||
bool Sync::isReadyToSync()const{
|
||||
return !fbroadcaster && player->isSeekable()
|
||||
return !node->isBroadcaster() && player->isSeekable()
|
||||
&& (player->state() == QMediaPlayer::PlayingState);
|
||||
|
||||
}
|
||||
|
||||
bool Sync::sync(const Syncer &sync, milliseconds ping){
|
||||
if(!isReadyToSync()){
|
||||
bool Sync::sync(const Syncer &sync){
|
||||
milliseconds now = sync.timeOn - ChronoTime::now();
|
||||
if(!isReadyToSync() || now < 0 || now > SYNC_TIME){
|
||||
return false;
|
||||
}
|
||||
player->setPosition(sync.seek + ping);
|
||||
|
||||
// QTimer::singleShot(now, [=](){
|
||||
// player->setPosition(sync.seek);
|
||||
|
||||
// player->syncEnd();
|
||||
// } );
|
||||
|
||||
while (ChronoTime::now() < sync.timeOn) { }
|
||||
player->setPosition(sync.seek);
|
||||
player->syncEnd();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo thi nead send a hedaer
|
||||
*/
|
||||
void Sync::sync(){
|
||||
|
||||
if(fbroadcaster)
|
||||
QTimer::singleShot(SYNC_TIME, [=]() {
|
||||
if(node->isBroadcaster()) {
|
||||
for(ETcpSocket *i: *node->getClients()){
|
||||
sync(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sync::sync(ETcpSocket* socket){
|
||||
|
||||
if(node->isBroadcaster()) {
|
||||
|
||||
if(!socket->isSynced()){
|
||||
socket->sync();
|
||||
return;
|
||||
}
|
||||
|
||||
package pac;
|
||||
if(!createPackage(t_sync, pac, socket->getTime())){
|
||||
CreatePackageExaption();
|
||||
return;
|
||||
}
|
||||
node->WriteAll(pac.parseTo());
|
||||
}
|
||||
|
||||
package pac;
|
||||
if(!createPackage(t_sync, pac)){
|
||||
CreatePackageExaption();
|
||||
return;
|
||||
}
|
||||
node->WriteAll(pac.parseTo());
|
||||
});
|
||||
}
|
||||
|
||||
bool Sync::addNode(const QString ip, int port){
|
||||
@ -267,6 +274,10 @@ bool Sync::listen(ETcpSocket *server){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!server->isValid()){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!server->getSource()->isOpen() && server->getSource()->open(QIODevice::ReadWrite)){
|
||||
return false;
|
||||
}
|
||||
@ -279,28 +290,28 @@ bool Sync::listen(ETcpSocket *server){
|
||||
return server->Write(pac.parseTo());
|
||||
}
|
||||
|
||||
bool Sync::createPackage(Type type, package &pac){
|
||||
bool Sync::createPackage(Type type, package &pac, milliseconds time){
|
||||
|
||||
pac.clear();
|
||||
|
||||
pac.type = type;
|
||||
|
||||
if(type & TypePackage::t_sync){
|
||||
if(fbroadcaster)
|
||||
pac.playdata.seek = player->position();
|
||||
else
|
||||
lastSyncTime = ChronoTime::now();
|
||||
bool isbroadcaster = node->isBroadcaster();
|
||||
|
||||
if(type & TypePackage::t_sync && isbroadcaster){
|
||||
pac.playdata.seek = player->position() + SYNC_TIME;
|
||||
pac.playdata.timeOn = ChronoTime::now(time) + SYNC_TIME;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h && fbroadcaster){
|
||||
if(type & TypePackage::t_song_h && isbroadcaster ){
|
||||
if(playList->getList()->currentIndex() < 0)
|
||||
return false;
|
||||
|
||||
pac.header = *playList->currentHeader();
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song && fbroadcaster){
|
||||
if(type & TypePackage::t_song && isbroadcaster){
|
||||
if(playList->getList()->currentIndex() < 0)
|
||||
return false;
|
||||
|
||||
@ -309,7 +320,7 @@ bool Sync::createPackage(Type type, package &pac){
|
||||
|
||||
}
|
||||
|
||||
if(fbroadcaster)
|
||||
if(isbroadcaster)
|
||||
pac.type = TypePackage(pac.type | t_brodcaster);
|
||||
|
||||
return pac.isValid();
|
||||
@ -321,7 +332,6 @@ void Sync::packageRender(ETcpSocket *socket){
|
||||
while((array = socket->topStack())){
|
||||
package pkg;
|
||||
if(!pkg.parseFrom((*array))){
|
||||
throw BadAnswerExaption();
|
||||
socket->nextItem();
|
||||
continue;
|
||||
}
|
||||
@ -339,44 +349,22 @@ void Sync::packageRender(ETcpSocket *socket){
|
||||
emit networkStateChange();
|
||||
}
|
||||
|
||||
if(pkg.getType() & t_brodcaster){
|
||||
if(pkg.getType() & t_brodcaster && !node->isBroadcaster()){
|
||||
|
||||
// if requst from server
|
||||
|
||||
// calc ping for sync
|
||||
bool fFromRequst = false;
|
||||
if(lastSyncTime){
|
||||
ping = ChronoTime::now() - lastSyncTime;
|
||||
lastSyncTime = 0;
|
||||
fFromRequst = true;
|
||||
if(pkg.getType() & t_pause){
|
||||
pause(true);
|
||||
}
|
||||
|
||||
if(pkg.getType() & t_sync &&
|
||||
!sync(pkg.getPlayData(), (fFromRequst)? ping: ping/2)){
|
||||
if(pkg.getType() & t_sync && !sync(pkg.getPlayData())){
|
||||
|
||||
QTimer::singleShot(RESYNC_TIME, [=]() {
|
||||
package pac;
|
||||
|
||||
if(resyncCount < MAX_RESYNC_COUNT){
|
||||
|
||||
if(!createPackage(t_sync, pac)){
|
||||
throw CreatePackageExaption();
|
||||
return;
|
||||
}
|
||||
resyncCount++;
|
||||
|
||||
}else{
|
||||
resyncCount = 0;
|
||||
throw SyncCountError();
|
||||
return;
|
||||
}
|
||||
|
||||
node->WriteAll(pac.parseTo());
|
||||
});
|
||||
|
||||
}
|
||||
else if (pkg.getType() & t_sync){
|
||||
resyncCount = 0;
|
||||
package answer;
|
||||
if(!createPackage(t_sync, answer)){
|
||||
CreatePackageExaption();
|
||||
socket->nextItem();
|
||||
}
|
||||
socket->Write(answer.parseTo());
|
||||
}
|
||||
|
||||
if(pkg.getType() & t_play && !play(pkg.getHeader(), false) && !play(pkg.getSong(), false)){
|
||||
@ -388,7 +376,6 @@ void Sync::packageRender(ETcpSocket *socket){
|
||||
|
||||
package answer;
|
||||
if(!createPackage(requestType | t_play, answer)){
|
||||
throw CreatePackageExaption();
|
||||
socket->nextItem();
|
||||
continue;
|
||||
}
|
||||
@ -398,18 +385,17 @@ void Sync::packageRender(ETcpSocket *socket){
|
||||
|
||||
package answer;
|
||||
if(!createPackage(t_sync, answer)){
|
||||
throw CreatePackageExaption();
|
||||
socket->nextItem();
|
||||
continue;
|
||||
}
|
||||
socket->Write(answer.parseTo());
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(pkg.getType() & t_close){
|
||||
socket->getSource()->close();
|
||||
node->getClients()->removeOne(socket);
|
||||
servers.removeOne(socket);
|
||||
emit networkStateChange();
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
@ -417,37 +403,34 @@ void Sync::packageRender(ETcpSocket *socket){
|
||||
if(pkg.getType() & t_what){
|
||||
package answer;
|
||||
if(!createPackage(t_void, answer)){
|
||||
throw CreatePackageExaption();
|
||||
socket->nextItem();
|
||||
continue;
|
||||
}
|
||||
socket->Write(answer.parseTo());
|
||||
}
|
||||
|
||||
}else{
|
||||
} else if (node->isBroadcaster()) {
|
||||
// if requst from client
|
||||
|
||||
// if requst from client
|
||||
if(pkg.getType() & t_play & t_sync){
|
||||
if(playList->getList()->currentIndex() < 0){
|
||||
throw SyncError();
|
||||
socket->nextItem();
|
||||
continue;
|
||||
if(pkg.getType() & t_sync){
|
||||
if(socket->isSynced()){
|
||||
sync(socket);
|
||||
} else {
|
||||
socket->sync();
|
||||
}
|
||||
}
|
||||
|
||||
package answer;
|
||||
if(!createPackage(pkg.getType() & ~t_what & ~t_stop & ~t_brodcaster, answer)){
|
||||
throw CreatePackageExaption();
|
||||
socket->nextItem();
|
||||
continue;
|
||||
}
|
||||
socket->Write(answer.parseTo());
|
||||
|
||||
package answer;
|
||||
if(createPackage(pkg.getType() & ~t_sync & ~t_pause & ~t_what & ~t_close & ~t_brodcaster, answer)){
|
||||
socket->Write(answer.parseTo());
|
||||
}
|
||||
|
||||
if(pkg.getType() & t_close){
|
||||
socket->getSource()->close();
|
||||
node->getClients()->removeOne(socket);
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
@ -459,7 +442,6 @@ void Sync::packageRender(ETcpSocket *socket){
|
||||
void Sync::rescan(bool deep){
|
||||
package pac;
|
||||
if(!createPackage(t_what, pac)){
|
||||
throw CreatePackageExaption();
|
||||
return;
|
||||
}
|
||||
node->WriteAll(pac.parseTo());
|
||||
@ -473,7 +455,6 @@ void Sync::rescan(bool deep){
|
||||
void Sync::deepScaned(QList<ETcpSocket *> * list){
|
||||
package pac;
|
||||
if(!createPackage(t_what, pac)){
|
||||
throw CreatePackageExaption();
|
||||
return;
|
||||
}
|
||||
QByteArray array = pac.parseTo();
|
||||
@ -487,7 +468,7 @@ void Sync::endPlay(QMediaPlayer::State state){
|
||||
|
||||
switch (state) {
|
||||
case QMediaPlayer::StoppedState:
|
||||
fbroadcaster = false;
|
||||
node->setBroadcaster(false);
|
||||
break;
|
||||
case QMediaPlayer::PlayingState:
|
||||
sync();
|
||||
@ -495,8 +476,6 @@ void Sync::endPlay(QMediaPlayer::State state){
|
||||
|
||||
case QMediaPlayer::PausedState:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
emit playStateChanged();
|
||||
@ -511,17 +490,17 @@ bool Sync::setValume(unsigned int valume){
|
||||
if(valume > 100 || !player->isSynced())
|
||||
return false;
|
||||
|
||||
player->setVolume(valume);
|
||||
player->setVolume(static_cast<int>(valume));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int Sync::getValume() const{
|
||||
return player->volume();
|
||||
return static_cast<unsigned int>(player->volume());
|
||||
}
|
||||
|
||||
unsigned int Sync::seek() const{
|
||||
return player->position();
|
||||
return static_cast<unsigned int>(player->position());
|
||||
}
|
||||
|
||||
const QList<SongStorage>* Sync::getPlayList() const{
|
||||
@ -554,8 +533,8 @@ bool Sync::updatePlayList(const QString &_playList){
|
||||
if(!playList->size())
|
||||
return false;
|
||||
|
||||
if(fbroadcaster){
|
||||
play(fbroadcaster);
|
||||
if(node->isBroadcaster()){
|
||||
play(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -584,6 +563,10 @@ QMediaPlayer::State Sync::playState()const{
|
||||
return player->state();
|
||||
}
|
||||
|
||||
void Sync::clientSynced(ETcpSocket* socket){
|
||||
sync(socket);
|
||||
}
|
||||
|
||||
Sync::~Sync(){
|
||||
delete node;
|
||||
delete player;
|
||||
@ -593,6 +576,5 @@ Sync::~Sync(){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
28
sync/sync.h
28
sync/sync.h
@ -10,8 +10,6 @@
|
||||
#include "player.h"
|
||||
#include "playlist.h"
|
||||
|
||||
namespace syncLib {
|
||||
|
||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> Clock;
|
||||
|
||||
class Node;
|
||||
@ -30,10 +28,6 @@ private:
|
||||
PlayList *playList;
|
||||
QString lastUsedPlayList;
|
||||
QList<ETcpSocket*> servers;
|
||||
bool fbroadcaster;
|
||||
int resyncCount;
|
||||
int lastSyncTime;
|
||||
int ping;
|
||||
LocalScanner deepScaner;
|
||||
MySql *sql;
|
||||
int port;
|
||||
@ -50,15 +44,17 @@ private:
|
||||
* @param pac - the resulting value
|
||||
* @return true if everything's done
|
||||
*/
|
||||
bool createPackage(Type type , package& pac);
|
||||
bool createPackage(Type type , package& pac, milliseconds time = 0);
|
||||
|
||||
private slots:
|
||||
|
||||
void clientSynced(ETcpSocket*);
|
||||
|
||||
/**
|
||||
* @brief setSingle set singl or temp playlist
|
||||
* @return true if all done
|
||||
*/
|
||||
bool setSingle(const QMediaContent& media);
|
||||
bool setSingle(const SongStorage &media);
|
||||
|
||||
/**
|
||||
* @brief updateSongs use method update avelable songs from sql database
|
||||
@ -115,14 +111,6 @@ public:
|
||||
*/
|
||||
bool play(bool fbroadcast = true);
|
||||
|
||||
/**
|
||||
* @brief Play song in this device, if device has not supported playning media data this method throw MediaExcrption.
|
||||
* @param header of song
|
||||
* @param fbroadcast - server broadcasting sound.
|
||||
* @return true if all done else false.
|
||||
*/
|
||||
bool play(const QMediaContent &media, bool fbroadcast = true);
|
||||
|
||||
/**
|
||||
* @brief Play song in this device, if device has not supported playning media data this method throw MediaExcrption.
|
||||
* @param header of song
|
||||
@ -179,7 +167,7 @@ public:
|
||||
* @brief sync with server
|
||||
* @param sync - data of sync
|
||||
*/
|
||||
bool sync(const Syncer& sync, milliseconds ping);
|
||||
bool sync(const Syncer& sync);
|
||||
|
||||
/**
|
||||
* @brief isReadyToSync
|
||||
@ -192,6 +180,11 @@ public:
|
||||
*/
|
||||
void sync();
|
||||
|
||||
/**
|
||||
* @brief sync with clients
|
||||
*/
|
||||
void sync(ETcpSocket *socket);
|
||||
|
||||
/**
|
||||
* @brief addNode add new connect
|
||||
* @param ip of connection
|
||||
@ -345,7 +338,6 @@ signals:
|
||||
void playStateChanged();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // SYNC_H
|
||||
|
113
sync/syncpackage.cpp
Normal file
113
sync/syncpackage.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
#include "syncpackage.h"
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
|
||||
SyncPackage::SyncPackage()
|
||||
{
|
||||
type = TypeSyncPackage::t_voidSync;
|
||||
firstByte = sourceBytes = 0;
|
||||
}
|
||||
|
||||
bool SyncPackage::isValid() const{
|
||||
|
||||
switch (type) {
|
||||
case TypeSyncPackage::t_voidSync:
|
||||
return false;
|
||||
|
||||
case TypeSyncPackage::t_Header:
|
||||
return firstByte >= 0;
|
||||
|
||||
default:
|
||||
return firstByte >= 0 && sourceBytes != 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SyncPackage::clear(){
|
||||
type = TypeSyncPackage::t_voidSync;
|
||||
firstByte = 0;
|
||||
sourceBytes = 0;
|
||||
}
|
||||
|
||||
QByteArray SyncPackage::parseTo(){
|
||||
QByteArray temp;
|
||||
QDataStream stream(&temp, QIODevice::WriteOnly);
|
||||
temp.clear();
|
||||
if(isValid()){
|
||||
stream << static_cast<unsigned char>(type);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case TypeSyncPackage::t_End:
|
||||
stream << firstByte;
|
||||
stream << sourceBytes;
|
||||
stream << nativeTime;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
stream << firstByte;
|
||||
stream << sourceBytes;
|
||||
|
||||
}
|
||||
} else {
|
||||
qDebug() << "package synk is not valid!!!";
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool SyncPackage::parseFrom(QByteArray &array){
|
||||
type = TypeSyncPackage::t_voidSync;
|
||||
QDataStream stream(&array, QIODevice::ReadOnly);
|
||||
|
||||
unsigned char temp_type;
|
||||
stream >> temp_type;
|
||||
type = static_cast<TypeSyncPackage> (temp_type);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case TypeSyncPackage::t_End:
|
||||
stream >> firstByte;
|
||||
stream >> sourceBytes;
|
||||
stream >> nativeTime;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
stream >> firstByte;
|
||||
stream >> sourceBytes;
|
||||
|
||||
}
|
||||
|
||||
return isValid();
|
||||
}
|
||||
|
||||
TypeSyncPackage SyncPackage::getType()const {
|
||||
return type;
|
||||
}
|
||||
|
||||
char SyncPackage::getIndex()const {
|
||||
return firstByte;
|
||||
}
|
||||
|
||||
const milliseconds& SyncPackage::getNative()const {
|
||||
return nativeTime;
|
||||
}
|
||||
|
||||
const milliseconds& SyncPackage::getTime()const {
|
||||
return sourceBytes;
|
||||
}
|
||||
|
||||
const milliseconds& SyncPackage::getPing()const {
|
||||
return sourceBytes;
|
||||
}
|
||||
|
||||
char SyncPackage::getPrecision()const {
|
||||
return firstByte;
|
||||
}
|
||||
|
||||
bool SyncPackage::isSended()const {
|
||||
return type == TypeSyncPackage::t_Responce && firstByte;
|
||||
}
|
||||
|
||||
SyncPackage::~SyncPackage(){}
|
100
sync/syncpackage.h
Normal file
100
sync/syncpackage.h
Normal file
@ -0,0 +1,100 @@
|
||||
#ifndef SYNCPACKAGE_H
|
||||
#define SYNCPACKAGE_H
|
||||
|
||||
#include "chronotime.h"
|
||||
#include <QByteArray>
|
||||
|
||||
class ETcpSocket;
|
||||
|
||||
enum TypeSyncPackage{
|
||||
t_voidSync = 0x00,
|
||||
t_Header = 0x01,
|
||||
t_Responce = 0x02,
|
||||
t_Source = 0x04,
|
||||
t_End = 0x08
|
||||
};
|
||||
|
||||
class SyncPackage
|
||||
{
|
||||
private:
|
||||
|
||||
TypeSyncPackage type;
|
||||
qint8 firstByte;
|
||||
milliseconds ping;
|
||||
milliseconds nativeTime;
|
||||
milliseconds sourceBytes;
|
||||
|
||||
public:
|
||||
SyncPackage();
|
||||
|
||||
/**
|
||||
* @brief getType
|
||||
* @return type of package
|
||||
*/
|
||||
TypeSyncPackage getType() const;
|
||||
|
||||
/**
|
||||
* @brief getIndex
|
||||
* @return return index
|
||||
*/
|
||||
char getIndex()const;
|
||||
|
||||
/**
|
||||
* @brief getDelay
|
||||
* @return return delay
|
||||
*/
|
||||
const milliseconds& getNative()const;
|
||||
|
||||
/**
|
||||
* @brief getTime
|
||||
* @return time
|
||||
*/
|
||||
const milliseconds& getTime()const;
|
||||
|
||||
/**
|
||||
* @brief getPing
|
||||
* @return ping
|
||||
*/
|
||||
const milliseconds& getPing()const;
|
||||
|
||||
/**
|
||||
* @brief getPrecision
|
||||
* @return precision
|
||||
*/
|
||||
char getPrecision()const;
|
||||
|
||||
/**
|
||||
* @brief isSended
|
||||
* @return true if package sended
|
||||
*/
|
||||
bool isSended()const;
|
||||
|
||||
/**
|
||||
* @brief isValid
|
||||
* @return true if package is valid
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @brief clear all date of package
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @brief parseTo parse this package to byte array
|
||||
* @return byte array
|
||||
*/
|
||||
QByteArray parseTo();
|
||||
|
||||
/**
|
||||
* @brief parseFrom create a package from bytes
|
||||
* @param array of bytes
|
||||
* @return true if package valid
|
||||
*/
|
||||
bool parseFrom(QByteArray& array);
|
||||
|
||||
~SyncPackage();
|
||||
friend class ETcpSocket;
|
||||
};
|
||||
|
||||
#endif // SYNCPACKAGE_H
|
11
testLocalTimer/main.cpp
Normal file
11
testLocalTimer/main.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
39
testLocalTimer/mainwindow.cpp
Normal file
39
testLocalTimer/mainwindow.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include <QLabel>
|
||||
#include <QDateTime>
|
||||
#include <QKeyEvent>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow) {
|
||||
ui->setupUi(this);
|
||||
timer.setInterval(0);
|
||||
color = Qt::white;
|
||||
connect(&timer, &QTimer::timeout, this, &MainWindow::handleTick);
|
||||
timer.start();
|
||||
}
|
||||
|
||||
void MainWindow::keyPressEvent(QKeyEvent * key) {
|
||||
|
||||
if (key->key() == Qt::Key_Space) {
|
||||
if (timer.isActive()) {
|
||||
timer.stop();
|
||||
} else {
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::handleTick() {
|
||||
|
||||
auto time = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
ui->msec->setText(QString::number(time));
|
||||
}
|
28
testLocalTimer/mainwindow.h
Normal file
28
testLocalTimer/mainwindow.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
void keyPressEvent(QKeyEvent*);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
QTimer timer;
|
||||
QColor color;
|
||||
Ui::MainWindow *ui;
|
||||
private slots:
|
||||
void handleTick();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
66
testLocalTimer/mainwindow.ui
Normal file
66
testLocalTimer/mainwindow.ui
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="msec">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 48pt "Ubuntu";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="mainToolBar">
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
38
testLocalTimer/testLocalTimer.pro
Normal file
38
testLocalTimer/testLocalTimer.pro
Normal file
@ -0,0 +1,38 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2018-08-16T20:39:30
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui widgets
|
||||
|
||||
TARGET = testLocalTimer
|
||||
TEMPLATE = app
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
Loading…
x
Reference in New Issue
Block a user