Merge pull request #69 from QuasarApp/fixSync2

fix sync
This commit is contained in:
Andrei Yankovich 2018-08-16 22:45:35 +03:00 committed by GitHub
commit 7b6e435460
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1116 additions and 447 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -17,7 +17,7 @@ class CurrentPlayListModel : public QAbstractListModel
private:
SyncEngine * syncEngine;
const QList<syncLib::SongStorage> *playList;
const QList<SongStorage> *playList;
int itemCount;
private slots:

View File

@ -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;
}

View File

@ -16,7 +16,7 @@ class PlayListModel : public QAbstractListModel
private:
SyncEngine * syncEngine;
QList<syncLib::SongStorage> playList;
QList<SongStorage> playList;
QString playListName;
int itemCount;

View File

@ -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;

View File

@ -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;

View File

@ -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)){

View File

@ -20,8 +20,8 @@ class SyncEngine : public QObject
private:
syncLib::Sync *sync;
syncLib::MySql * sqlApi;
Sync *sync;
MySql * sqlApi;
QString _lastError;
QSettings settings;

View File

@ -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)));

View File

@ -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
View 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
View 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

View File

@ -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){

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -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

View File

@ -3,8 +3,6 @@
#include <QMediaPlaylist>
#include "song.h"
using namespace syncLib;
/**
* @brief The PlayList class
* palyList with songs info

View File

@ -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;
}
}

View File

@ -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

View File

@ -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(){
}
}

View File

@ -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
View 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
View 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
View 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();
}

View 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));
}

View 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

View 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 &quot;Ubuntu&quot;;</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>

View 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