From 5a24868fae1dd0c1b42b61cd66e09d01cf96d9d1 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 09:13:18 +0300 Subject: [PATCH 01/10] fix sync --- SoundBand/SoundBand.pro | 8 +- SoundBand/currentplaylistmodel.cpp | 8 +- SoundBand/currentplaylistmodel.h | 2 +- SoundBand/playlistmodel.cpp | 10 +- SoundBand/playlistmodel.h | 2 +- SoundBand/playlistsmodel.cpp | 4 +- SoundBand/serverlistmodel.cpp | 4 +- SoundBand/syncengine.cpp | 10 +- SoundBand/syncengine.h | 4 +- sync/ETcpSocket.cpp | 178 ++++++++++++++++++++++-- sync/ETcpSocket.h | 71 +++++++++- sync/basepackage.cpp | 118 ++++++++++++++++ sync/basepackage.h | 112 +++++++++++++++ sync/chronotime.cpp | 2 +- sync/chronotime.h | 2 +- sync/config.h | 2 +- sync/mysql.cpp | 47 +------ sync/mysql.h | 21 +-- sync/node.cpp | 137 +++---------------- sync/node.h | 141 ++++++++++--------- sync/playlist.h | 2 - sync/song.cpp | 7 +- sync/song.h | 8 +- sync/sync.cpp | 212 +++++++++++++---------------- sync/sync.h | 28 ++-- sync/syncpackage.cpp | 113 +++++++++++++++ sync/syncpackage.h | 100 ++++++++++++++ 27 files changed, 912 insertions(+), 441 deletions(-) create mode 100644 sync/basepackage.cpp create mode 100644 sync/basepackage.h create mode 100644 sync/syncpackage.cpp create mode 100644 sync/syncpackage.h diff --git a/SoundBand/SoundBand.pro b/SoundBand/SoundBand.pro index c89350c..3aaedfa 100644 --- a/SoundBand/SoundBand.pro +++ b/SoundBand/SoundBand.pro @@ -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 diff --git a/SoundBand/currentplaylistmodel.cpp b/SoundBand/currentplaylistmodel.cpp index fbaa202..5a6381e 100644 --- a/SoundBand/currentplaylistmodel.cpp +++ b/SoundBand/currentplaylistmodel.cpp @@ -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; } diff --git a/SoundBand/currentplaylistmodel.h b/SoundBand/currentplaylistmodel.h index 0809d81..79f8bf4 100644 --- a/SoundBand/currentplaylistmodel.h +++ b/SoundBand/currentplaylistmodel.h @@ -17,7 +17,7 @@ class CurrentPlayListModel : public QAbstractListModel private: SyncEngine * syncEngine; - const QList *playList; + const QList *playList; int itemCount; private slots: diff --git a/SoundBand/playlistmodel.cpp b/SoundBand/playlistmodel.cpp index 9e03ba8..b0b8ae3 100644 --- a/SoundBand/playlistmodel.cpp +++ b/SoundBand/playlistmodel.cpp @@ -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::Iterator i = playList.begin(); i < playList.end(); i++){ + for(QList::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 PlayListModel::getSelected(){ QList result; - for(QList::Iterator i = playList.begin(); i < playList.end(); i++){ + for(QList::Iterator i = playList.begin(); i < playList.end(); i++){ if(i->isSelected){ result.push_back(i->id); } @@ -124,7 +122,7 @@ QList PlayListModel::getSelected(){ bool PlayListModel::isSelected(int id){ - for(QList::Iterator i = playList.begin(); i < playList.end(); i++){ + for(QList::Iterator i = playList.begin(); i < playList.end(); i++){ if(i->id == id){ return i->isSelected; } diff --git a/SoundBand/playlistmodel.h b/SoundBand/playlistmodel.h index bc8d143..d5ad3c0 100644 --- a/SoundBand/playlistmodel.h +++ b/SoundBand/playlistmodel.h @@ -16,7 +16,7 @@ class PlayListModel : public QAbstractListModel private: SyncEngine * syncEngine; - QList playList; + QList playList; QString playListName; int itemCount; diff --git a/SoundBand/playlistsmodel.cpp b/SoundBand/playlistsmodel.cpp index 1493e30..3e52296 100644 --- a/SoundBand/playlistsmodel.cpp +++ b/SoundBand/playlistsmodel.cpp @@ -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; diff --git a/SoundBand/serverlistmodel.cpp b/SoundBand/serverlistmodel.cpp index 955378c..50cce72 100644 --- a/SoundBand/serverlistmodel.cpp +++ b/SoundBand/serverlistmodel.cpp @@ -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; diff --git a/SoundBand/syncengine.cpp b/SoundBand/syncengine.cpp index 1eb35da..a16077d 100644 --- a/SoundBand/syncengine.cpp +++ b/SoundBand/syncengine.cpp @@ -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* SyncEngine::currentPlayList() const{ +const QList* 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)){ diff --git a/SoundBand/syncengine.h b/SoundBand/syncengine.h index 6be2ad1..5b3456e 100644 --- a/SoundBand/syncengine.h +++ b/SoundBand/syncengine.h @@ -20,8 +20,8 @@ class SyncEngine : public QObject private: - syncLib::Sync *sync; - syncLib::MySql * sqlApi; + Sync *sync; + MySql * sqlApi; QString _lastError; QSettings settings; diff --git a/sync/ETcpSocket.cpp b/sync/ETcpSocket.cpp index df24d2c..74dca41 100755 --- a/sync/ETcpSocket.cpp +++ b/sync/ETcpSocket.cpp @@ -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,133 @@ 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 > 2) { + return false; + } + + time = from.getNative() - syncList[from.getIndex()].getTime() - from.getPing() / 2; + fSynced = true; + + 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 +189,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 +223,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 +266,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<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))); diff --git a/sync/ETcpSocket.h b/sync/ETcpSocket.h index aabcec6..a45c52a 100755 --- a/sync/ETcpSocket.h +++ b/sync/ETcpSocket.h @@ -4,7 +4,7 @@ #include #include #include -#include "chronotime.h" +#include "syncpackage.h" /** @@ -36,9 +36,41 @@ private: QTcpSocket *source; QByteArray *array; qint32 size; + milliseconds time; + milliseconds lastTime; + char precisionSync; QList ReadyStack; + bool fSynced; + QMap 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 diff --git a/sync/basepackage.cpp b/sync/basepackage.cpp new file mode 100644 index 0000000..c3c7f74 --- /dev/null +++ b/sync/basepackage.cpp @@ -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(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 (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(){} + diff --git a/sync/basepackage.h b/sync/basepackage.h new file mode 100644 index 0000000..6d85c16 --- /dev/null +++ b/sync/basepackage.h @@ -0,0 +1,112 @@ +#ifndef BASEPACKAGE_H +#define BASEPACKAGE_H + +#include "song.h" +#include "config.h" +#include + +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 diff --git a/sync/chronotime.cpp b/sync/chronotime.cpp index 11eb070..7f11a21 100644 --- a/sync/chronotime.cpp +++ b/sync/chronotime.cpp @@ -11,7 +11,7 @@ ChronoTime::ChronoTime() * https://stackoverflow.com/questions/31255486/c-how-do-i-convert-a-stdchronotime-point-to-long-and-back */ -milliseconds ChronoTime::now(int calibration){ +milliseconds ChronoTime::now(milliseconds calibration){ auto tim = std::chrono::system_clock::now(); auto mc = std::chrono::time_point_cast(tim); auto epoh = mc.time_since_epoch(); diff --git a/sync/chronotime.h b/sync/chronotime.h index ee17b60..59c8ffb 100644 --- a/sync/chronotime.h +++ b/sync/chronotime.h @@ -17,7 +17,7 @@ public: * @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 diff --git a/sync/config.h b/sync/config.h index 4988bef..7d65efa 100644 --- a/sync/config.h +++ b/sync/config.h @@ -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 10 #define DEEP_SCANER_INTERVAL 1000 // 1 sec -#define CHECK_PING_INTERVAL 5 * 60 *1000// 5 minutes // sync #define MIN_DIFFERENCE 10 // millisec diff --git a/sync/mysql.cpp b/sync/mysql.cpp index faaedc1..8628801 100644 --- a/sync/mysql.cpp +++ b/sync/mysql.cpp @@ -5,8 +5,6 @@ #include #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 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 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 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); } -} + diff --git a/sync/mysql.h b/sync/mysql.h index e5ab00d..9939f65 100644 --- a/sync/mysql.h +++ b/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 diff --git a/sync/node.cpp b/sync/node.cpp index d4da3fc..be6260a 100644 --- a/sync/node.cpp +++ b/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(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 (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* Node::getClients(){ return &clients; } @@ -152,11 +49,18 @@ QList* 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(this->sender())); +} + void Node::readData(ETcpSocket *c){ emit Message(c); } @@ -211,6 +115,5 @@ Node::~Node(){ this->close(); } -} diff --git a/sync/node.h b/sync/node.h index 330b60a..d8fc79d 100644 --- a/sync/node.h +++ b/sync/node.h @@ -2,104 +2,101 @@ #define NODE_H #include #include "ETcpSocket.h" -#include "song.h" -#include "config.h" - -namespace syncLib { - -typedef unsigned char Type; +#include +#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 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* 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 diff --git a/sync/playlist.h b/sync/playlist.h index 256b40b..3dd0ed0 100644 --- a/sync/playlist.h +++ b/sync/playlist.h @@ -3,8 +3,6 @@ #include #include "song.h" -using namespace syncLib; - /** * @brief The PlayList class * palyList with songs info diff --git a/sync/song.cpp b/sync/song.cpp index abfc11d..53ac7e2 100644 --- a/sync/song.cpp +++ b/sync/song.cpp @@ -3,8 +3,6 @@ #include #include -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; } -} diff --git a/sync/song.h b/sync/song.h index 54aa297..fd2ca0e 100644 --- a/sync/song.h +++ b/sync/song.h @@ -6,8 +6,6 @@ #include "chronotime.h" #include -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 diff --git a/sync/sync.cpp b/sync/sync.cpp index 2744448..adff782 100644 --- a/sync/sync.cpp +++ b/sync/sync.cpp @@ -10,8 +10,6 @@ #include #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*)), SLOT(deepScaned(QList*))); 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(song), savedSong) && sql->save(song) > -1 && - !sql->find((SongHeader&)song, savedSong)){ + !sql->find(static_cast(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,58 @@ 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){ return false; } - player->setPosition(sync.seek + ping); - player->syncEnd(); + + QTimer::singleShot(now, [=](){ + 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 +270,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 +286,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 && time > 0){ + 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 +316,7 @@ bool Sync::createPackage(Type type, package &pac){ } - if(fbroadcaster) + if(isbroadcaster) pac.type = TypePackage(pac.type | t_brodcaster); return pac.isValid(); @@ -321,7 +328,6 @@ void Sync::packageRender(ETcpSocket *socket){ while((array = socket->topStack())){ package pkg; if(!pkg.parseFrom((*array))){ - throw BadAnswerExaption(); socket->nextItem(); continue; } @@ -339,44 +345,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 +372,6 @@ void Sync::packageRender(ETcpSocket *socket){ package answer; if(!createPackage(requestType | t_play, answer)){ - throw CreatePackageExaption(); socket->nextItem(); continue; } @@ -398,18 +381,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 +399,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 +438,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 +451,6 @@ void Sync::rescan(bool deep){ void Sync::deepScaned(QList * list){ package pac; if(!createPackage(t_what, pac)){ - throw CreatePackageExaption(); return; } QByteArray array = pac.parseTo(); @@ -487,7 +464,7 @@ void Sync::endPlay(QMediaPlayer::State state){ switch (state) { case QMediaPlayer::StoppedState: - fbroadcaster = false; + node->setBroadcaster(false); break; case QMediaPlayer::PlayingState: sync(); @@ -495,8 +472,6 @@ void Sync::endPlay(QMediaPlayer::State state){ case QMediaPlayer::PausedState: break; - default: - break; } emit playStateChanged(); @@ -511,17 +486,17 @@ bool Sync::setValume(unsigned int valume){ if(valume > 100 || !player->isSynced()) return false; - player->setVolume(valume); + player->setVolume(static_cast(valume)); return true; } unsigned int Sync::getValume() const{ - return player->volume(); + return static_cast(player->volume()); } unsigned int Sync::seek() const{ - return player->position(); + return static_cast(player->position()); } const QList* Sync::getPlayList() const{ @@ -554,8 +529,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 +559,10 @@ QMediaPlayer::State Sync::playState()const{ return player->state(); } +void Sync::clientSynced(ETcpSocket* socket){ + sync(socket); +} + Sync::~Sync(){ delete node; delete player; @@ -593,6 +572,5 @@ Sync::~Sync(){ } -} diff --git a/sync/sync.h b/sync/sync.h index 9c65010..2f51014 100644 --- a/sync/sync.h +++ b/sync/sync.h @@ -10,8 +10,6 @@ #include "player.h" #include "playlist.h" -namespace syncLib { - typedef std::chrono::time_point Clock; class Node; @@ -30,10 +28,6 @@ private: PlayList *playList; QString lastUsedPlayList; QList 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 diff --git a/sync/syncpackage.cpp b/sync/syncpackage.cpp new file mode 100644 index 0000000..97ce845 --- /dev/null +++ b/sync/syncpackage.cpp @@ -0,0 +1,113 @@ +#include "syncpackage.h" +#include +#include + +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(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 (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(){} diff --git a/sync/syncpackage.h b/sync/syncpackage.h new file mode 100644 index 0000000..7d06fe4 --- /dev/null +++ b/sync/syncpackage.h @@ -0,0 +1,100 @@ +#ifndef SYNCPACKAGE_H +#define SYNCPACKAGE_H + +#include "chronotime.h" +#include + +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 From 603252f7f358827a4b690f013d5a7212c7d21d77 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 09:46:47 +0300 Subject: [PATCH 02/10] qt and std times --- sync/ETcpSocket.cpp | 2 ++ sync/chronotime.cpp | 23 ++++++++++++++++------- sync/chronotime.h | 3 +++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/sync/ETcpSocket.cpp b/sync/ETcpSocket.cpp index 74dca41..f5dfff4 100755 --- a/sync/ETcpSocket.cpp +++ b/sync/ETcpSocket.cpp @@ -115,11 +115,13 @@ bool ETcpSocket::_driverResponse(const SyncPackage& from) { auto ping = from.getPing(); if (ping > 2) { + sync(); return false; } time = from.getNative() - syncList[from.getIndex()].getTime() - from.getPing() / 2; fSynced = true; + qDebug() << "syncTime :" << time; emit synced(); diff --git a/sync/chronotime.cpp b/sync/chronotime.cpp index 7f11a21..c355064 100644 --- a/sync/chronotime.cpp +++ b/sync/chronotime.cpp @@ -1,6 +1,21 @@ #include "chronotime.h" +#include #include +milliseconds ChronoTime::stdTime() { + auto tim = std::chrono::system_clock::now(); + auto mc = std::chrono::time_point_cast(tim); + auto epoh = mc.time_since_epoch(); +#ifdef QT_DEBUG + qDebug() << epoh.count(); +#endif + return epoh.count(); +} + +milliseconds ChronoTime::qtTime() { + return QDateTime::currentMSecsSinceEpoch(); +} + ChronoTime::ChronoTime() { @@ -12,13 +27,7 @@ ChronoTime::ChronoTime() */ milliseconds ChronoTime::now(milliseconds calibration){ - auto tim = std::chrono::system_clock::now(); - auto mc = std::chrono::time_point_cast(tim); - auto epoh = mc.time_since_epoch(); -#ifdef QT_DEBUG - qDebug() << epoh.count(); -#endif - return epoh.count() + calibration; + return qtTime() + calibration; } Clock ChronoTime::from(const milliseconds& mc){ diff --git a/sync/chronotime.h b/sync/chronotime.h index 59c8ffb..2f230c5 100644 --- a/sync/chronotime.h +++ b/sync/chronotime.h @@ -11,6 +11,9 @@ typedef std::chrono::time_point Clock; class ChronoTime { +private : + static milliseconds stdTime(); + static milliseconds qtTime(); public: ChronoTime(); /** From f6eae542dbf2ac609da6cf1a721b2ada4a26f63a Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 10:19:42 +0300 Subject: [PATCH 03/10] syncTime to force --- sync/chronotime.cpp | 9 ++++----- sync/sync.cpp | 16 +++++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/sync/chronotime.cpp b/sync/chronotime.cpp index c355064..fec3ee5 100644 --- a/sync/chronotime.cpp +++ b/sync/chronotime.cpp @@ -2,6 +2,10 @@ #include #include +/* + * information about chrono + * https://stackoverflow.com/questions/31255486/c-how-do-i-convert-a-stdchronotime-point-to-long-and-back + */ milliseconds ChronoTime::stdTime() { auto tim = std::chrono::system_clock::now(); auto mc = std::chrono::time_point_cast(tim); @@ -21,11 +25,6 @@ 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(milliseconds calibration){ return qtTime() + calibration; } diff --git a/sync/sync.cpp b/sync/sync.cpp index adff782..3ab5225 100644 --- a/sync/sync.cpp +++ b/sync/sync.cpp @@ -206,15 +206,21 @@ bool Sync::isReadyToSync()const{ bool Sync::sync(const Syncer &sync){ milliseconds now = sync.timeOn - ChronoTime::now(); - if(!isReadyToSync() || now < 0){ + if(!isReadyToSync() || now < 0 || now > SYNC_TIME){ return false; } - QTimer::singleShot(now, [=](){ - player->setPosition(sync.seek); +// QTimer::singleShot(now, [=](){ +// player->setPosition(sync.seek); - player->syncEnd(); - } ); +// player->syncEnd(); +// } ); + + while (ChronoTime::now() < sync.timeOn) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + player->setPosition(sync.seek); + player->syncEnd(); return true; From af6e29f78469069993ac407fa021ac9cf04363db Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 10:48:39 +0300 Subject: [PATCH 04/10] fix create package --- sync/sync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/sync.cpp b/sync/sync.cpp index 3ab5225..0fdf16c 100644 --- a/sync/sync.cpp +++ b/sync/sync.cpp @@ -300,7 +300,7 @@ bool Sync::createPackage(Type type, package &pac, milliseconds time){ bool isbroadcaster = node->isBroadcaster(); - if(type & TypePackage::t_sync && isbroadcaster && time > 0){ + if(type & TypePackage::t_sync && isbroadcaster){ pac.playdata.seek = player->position() + SYNC_TIME; pac.playdata.timeOn = ChronoTime::now(time) + SYNC_TIME; From 6a9d112239b22540289e8ddb41f84afad3735d15 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 20:58:59 +0300 Subject: [PATCH 05/10] fix sync, timeout --- sync/sync.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sync/sync.cpp b/sync/sync.cpp index 0fdf16c..cb5d561 100644 --- a/sync/sync.cpp +++ b/sync/sync.cpp @@ -216,9 +216,7 @@ bool Sync::sync(const Syncer &sync){ // player->syncEnd(); // } ); - while (ChronoTime::now() < sync.timeOn) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + while (ChronoTime::now() < sync.timeOn) { } player->setPosition(sync.seek); player->syncEnd(); From 85f161f617350aa3efb8437de1a6069d86669019 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 20:59:30 +0300 Subject: [PATCH 06/10] add test pro --- testLocalTimer/main.cpp | 11 ++++++ testLocalTimer/mainwindow.cpp | 35 +++++++++++++++++ testLocalTimer/mainwindow.h | 27 +++++++++++++ testLocalTimer/mainwindow.ui | 64 +++++++++++++++++++++++++++++++ testLocalTimer/testLocalTimer.pro | 38 ++++++++++++++++++ 5 files changed, 175 insertions(+) create mode 100644 testLocalTimer/main.cpp create mode 100644 testLocalTimer/mainwindow.cpp create mode 100644 testLocalTimer/mainwindow.h create mode 100644 testLocalTimer/mainwindow.ui create mode 100644 testLocalTimer/testLocalTimer.pro diff --git a/testLocalTimer/main.cpp b/testLocalTimer/main.cpp new file mode 100644 index 0000000..b48f94e --- /dev/null +++ b/testLocalTimer/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/testLocalTimer/mainwindow.cpp b/testLocalTimer/mainwindow.cpp new file mode 100644 index 0000000..45a3dd4 --- /dev/null +++ b/testLocalTimer/mainwindow.cpp @@ -0,0 +1,35 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include + +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(); +} + +MainWindow::~MainWindow() { + delete ui; +} + +void MainWindow::handleTick() { + + auto time = QDateTime::currentMSecsSinceEpoch(); + + ui->msec->setText(QString::number( time% 1000)); + + if (!(time % 1000)) { + if (color == Qt::white) { + color = Qt::green; + } else { + color = Qt::white; + } + + ui->color->setStyleSheet(QString("background-color: '%0';").arg(color.name(QColor::HexRgb))); + } +} diff --git a/testLocalTimer/mainwindow.h b/testLocalTimer/mainwindow.h new file mode 100644 index 0000000..ad68c59 --- /dev/null +++ b/testLocalTimer/mainwindow.h @@ -0,0 +1,27 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + QTimer timer; + QColor color; + Ui::MainWindow *ui; +private slots: + void handleTick(); +}; + +#endif // MAINWINDOW_H diff --git a/testLocalTimer/mainwindow.ui b/testLocalTimer/mainwindow.ui new file mode 100644 index 0000000..55309b1 --- /dev/null +++ b/testLocalTimer/mainwindow.ui @@ -0,0 +1,64 @@ + + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + MainWindow + + + + + + + + + + + + + + + + background-color: rgb(138, 226, 52); + + + + + + + + + + + + + + 0 + 0 + 400 + 22 + + + + + + TopToolBarArea + + + false + + + + + + + + diff --git a/testLocalTimer/testLocalTimer.pro b/testLocalTimer/testLocalTimer.pro new file mode 100644 index 0000000..f90fb6b --- /dev/null +++ b/testLocalTimer/testLocalTimer.pro @@ -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 From 77c4fa3c147c185b676f5d83a368bf7cb61c8057 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 22:14:01 +0300 Subject: [PATCH 07/10] control key --- testLocalTimer/mainwindow.cpp | 26 +++++++++++++++----------- testLocalTimer/mainwindow.h | 1 + testLocalTimer/mainwindow.ui | 18 ++++++++++-------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/testLocalTimer/mainwindow.cpp b/testLocalTimer/mainwindow.cpp index 45a3dd4..fee2f98 100644 --- a/testLocalTimer/mainwindow.cpp +++ b/testLocalTimer/mainwindow.cpp @@ -2,6 +2,7 @@ #include "ui_mainwindow.h" #include #include +#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), @@ -13,6 +14,19 @@ MainWindow::MainWindow(QWidget *parent) : 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; } @@ -21,15 +35,5 @@ void MainWindow::handleTick() { auto time = QDateTime::currentMSecsSinceEpoch(); - ui->msec->setText(QString::number( time% 1000)); - - if (!(time % 1000)) { - if (color == Qt::white) { - color = Qt::green; - } else { - color = Qt::white; - } - - ui->color->setStyleSheet(QString("background-color: '%0';").arg(color.name(QColor::HexRgb))); - } + ui->msec->setText(QString::number(time)); } diff --git a/testLocalTimer/mainwindow.h b/testLocalTimer/mainwindow.h index ad68c59..8660148 100644 --- a/testLocalTimer/mainwindow.h +++ b/testLocalTimer/mainwindow.h @@ -14,6 +14,7 @@ class MainWindow : public QMainWindow public: explicit MainWindow(QWidget *parent = nullptr); + void keyPressEvent(QKeyEvent*); ~MainWindow(); private: diff --git a/testLocalTimer/mainwindow.ui b/testLocalTimer/mainwindow.ui index 55309b1..77e0bb3 100644 --- a/testLocalTimer/mainwindow.ui +++ b/testLocalTimer/mainwindow.ui @@ -19,19 +19,21 @@ - - - - - - - - background-color: rgb(138, 226, 52); + font: 48pt "Ubuntu"; + + true + + + Qt::AlignCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + From deada49ea8124c57f6aa4946010aa2d646a792fa Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 22:23:40 +0300 Subject: [PATCH 08/10] new value for limit ping --- sync/ETcpSocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/ETcpSocket.cpp b/sync/ETcpSocket.cpp index f5dfff4..d1e919a 100755 --- a/sync/ETcpSocket.cpp +++ b/sync/ETcpSocket.cpp @@ -114,7 +114,7 @@ bool ETcpSocket::_driverResponse(const SyncPackage& from) { auto ping = from.getPing(); - if (ping > 2) { + if (ping > 10) { sync(); return false; } From 72aaf5e065351b52a3ed376f6f31186f2ce6da64 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 22:29:25 +0300 Subject: [PATCH 09/10] fix count of sync --- sync/ETcpSocket.cpp | 1 - sync/config.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sync/ETcpSocket.cpp b/sync/ETcpSocket.cpp index d1e919a..afad175 100755 --- a/sync/ETcpSocket.cpp +++ b/sync/ETcpSocket.cpp @@ -115,7 +115,6 @@ bool ETcpSocket::_driverResponse(const SyncPackage& from) { auto ping = from.getPing(); if (ping > 10) { - sync(); return false; } diff --git a/sync/config.h b/sync/config.h index 7d65efa..10ed645 100644 --- a/sync/config.h +++ b/sync/config.h @@ -25,7 +25,7 @@ #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 10 +#define SYNC_COUNT 100 #define DEEP_SCANER_INTERVAL 1000 // 1 sec // sync From ec76344a5af3430f8b181fa011767fb09255e209 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 16 Aug 2018 22:43:55 +0300 Subject: [PATCH 10/10] sync count fix --- sync/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/config.h b/sync/config.h index 10ed645..dbefcbf 100644 --- a/sync/config.h +++ b/sync/config.h @@ -25,7 +25,7 @@ #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 100 +#define SYNC_COUNT 20 #define DEEP_SCANER_INTERVAL 1000 // 1 sec // sync