mirror of
https://github.com/QuasarApp/SoundBand.git
synced 2025-04-26 07:14:31 +00:00
commit
92c7fa39a2
144
sync/ETcpSocket.cpp
Executable file
144
sync/ETcpSocket.cpp
Executable file
@ -0,0 +1,144 @@
|
||||
#include "ETcpSocket.h"
|
||||
#include "exaptions.h"
|
||||
|
||||
ETcpSocket::ETcpSocket()
|
||||
{
|
||||
source=new QTcpSocket();
|
||||
init();
|
||||
}
|
||||
ETcpSocket::ETcpSocket(QTcpSocket*ptr)
|
||||
{
|
||||
source=ptr;
|
||||
init();
|
||||
}
|
||||
|
||||
ETcpSocket::ETcpSocket(const QString& address, int port){
|
||||
source = new QTcpSocket();
|
||||
if(!source->bind(QHostAddress(address),port) || !source->open(QIODevice::ReadWrite)){
|
||||
throw AddNodeExaption();
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
void ETcpSocket::init(){
|
||||
array=new QByteArray;
|
||||
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_()));
|
||||
}
|
||||
|
||||
void ETcpSocket::error_(QAbstractSocket::SocketError i){
|
||||
emit Error(this,i);
|
||||
}
|
||||
|
||||
void ETcpSocket::connected_(){
|
||||
emit Connected(this);
|
||||
}
|
||||
|
||||
void ETcpSocket::disconnected_(){
|
||||
emit Disconnected(this);
|
||||
}
|
||||
|
||||
void ETcpSocket::hostFound_(){
|
||||
emit HostFound(this);
|
||||
}
|
||||
|
||||
void ETcpSocket::proxyAuthenticationRequired_(const QNetworkProxy &proxy, QAuthenticator *authenticator){
|
||||
emit ProxyAuthenticationRequired(this,proxy,authenticator);
|
||||
}
|
||||
|
||||
void ETcpSocket::stateChanged_(QAbstractSocket::SocketState socketState){
|
||||
emit StateChanged(this,socketState);
|
||||
}
|
||||
|
||||
void ETcpSocket::readReady_(){
|
||||
bool sizewrite=array->isEmpty();
|
||||
//while(source->bytesAvailable())
|
||||
array->append(source->readAll());
|
||||
QDataStream stream(array,QIODevice::ReadOnly);
|
||||
if(sizewrite)
|
||||
stream>>size;
|
||||
#ifdef QT_DEBUG
|
||||
qDebug()<<"messae size:"<<size;
|
||||
qDebug()<<"message package size:"<<array->size();
|
||||
#endif
|
||||
if(size==array->size())
|
||||
{
|
||||
array->remove(0,sizeof(qint32));
|
||||
ReadyStack.push_back(array);
|
||||
array=new QByteArray();
|
||||
emit Message(this);
|
||||
}else{
|
||||
emit donwload(array->size(),size);
|
||||
}
|
||||
// emit ReadReady(this);
|
||||
}
|
||||
|
||||
QString ETcpSocket::name() const{
|
||||
return source->peerAddress().toString();
|
||||
}
|
||||
|
||||
QByteArray* ETcpSocket::topStack(){
|
||||
if(ReadyStack.size())
|
||||
return ReadyStack.front();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QTcpSocket* ETcpSocket::getSource()const{
|
||||
return source;
|
||||
}
|
||||
|
||||
void ETcpSocket::nextItem(){
|
||||
if( ReadyStack.size()){
|
||||
ReadyStack.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
int ETcpSocket::sizeDescriptPackege(){
|
||||
return sizeof(qint32);
|
||||
}
|
||||
|
||||
QString ETcpSocket::toStringTcp(){
|
||||
return source->peerAddress().toString();
|
||||
}
|
||||
|
||||
bool ETcpSocket::Write(const QByteArray&data){
|
||||
if(source->state()==QTcpSocket::ConnectedState){
|
||||
QByteArray array;
|
||||
QDataStream stream(&array,QIODevice::ReadWrite);
|
||||
stream<<qint32(0);
|
||||
//stream<<data;
|
||||
array.append(data);
|
||||
stream.device()->seek(0);
|
||||
stream<<qint32(array.size());
|
||||
#ifdef QT_DEBUG
|
||||
qDebug()<<"size :"<<array.size();
|
||||
qint64 temp= source->write(array);
|
||||
qDebug()<<"size write:"<<temp<<" size packege:"<<array.size();
|
||||
return temp==(array.size());
|
||||
#else
|
||||
return source->write(array)==(array.size());
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ETcpSocket::~ETcpSocket()
|
||||
{
|
||||
for(QByteArray*i:ReadyStack){
|
||||
i->clear();
|
||||
delete i;
|
||||
}
|
||||
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)));
|
||||
disconnect(source,SIGNAL(hostFound()),this,SLOT(hostFound_()));
|
||||
disconnect(source,SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),this,SLOT(proxyAuthenticationRequired_(const QNetworkProxy &, QAuthenticator *)));
|
||||
disconnect(source,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(stateChanged_(QAbstractSocket::SocketState)));
|
||||
disconnect(source,SIGNAL(readyRead()),this,SLOT(readReady_()));
|
||||
source->deleteLater();
|
||||
}
|
74
sync/ETcpSocket.h
Executable file
74
sync/ETcpSocket.h
Executable file
@ -0,0 +1,74 @@
|
||||
#ifndef CLIENT_H
|
||||
#define CLIENT_H
|
||||
#include <QTcpSocket>
|
||||
#include <QTcpServer>
|
||||
#include <QList>
|
||||
#include <QDataStream>
|
||||
|
||||
/**
|
||||
* @brief The ETcpSocket class
|
||||
* example :
|
||||
* ETcpSocket *tcp;
|
||||
* try{
|
||||
* tcp = new ETcpSocket(addres,port);
|
||||
* }catch(addNodeExaption e){
|
||||
* e.what();
|
||||
* }
|
||||
* QByteArray *array;
|
||||
* while(array = tcp.getSource()){
|
||||
* package pkg(*array);
|
||||
* package ans = ansver(pkg);
|
||||
* tcp.Write(ans);
|
||||
* array->clear();
|
||||
* delete array;
|
||||
*
|
||||
* }
|
||||
*
|
||||
*/
|
||||
class ETcpSocket:public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ name)
|
||||
private:
|
||||
QTcpSocket *source;
|
||||
QByteArray *array;
|
||||
qint32 size;
|
||||
QList<QByteArray*> ReadyStack;
|
||||
void init();
|
||||
|
||||
private slots:
|
||||
void connected_();
|
||||
void disconnected_();
|
||||
void error_(QAbstractSocket::SocketError socketError);
|
||||
void hostFound_();
|
||||
void readReady_();
|
||||
void proxyAuthenticationRequired_(const QNetworkProxy &proxy, QAuthenticator *authenticator);
|
||||
void stateChanged_(QAbstractSocket::SocketState socketState);
|
||||
public:
|
||||
explicit ETcpSocket();
|
||||
explicit ETcpSocket(QTcpSocket*);
|
||||
explicit ETcpSocket(const QString& addres,int port);
|
||||
QTcpSocket* getSource()const;
|
||||
QByteArray* topStack();
|
||||
void nextItem();
|
||||
int sizeDescriptPackege();
|
||||
bool Write(const QByteArray&);
|
||||
~ETcpSocket();
|
||||
public slots:
|
||||
QString name()const;
|
||||
QString toStringTcp();
|
||||
signals:
|
||||
void donwload(int val,int max);
|
||||
void ReadyComplit(ETcpSocket*,QDataStream&);
|
||||
void Connected(ETcpSocket*);
|
||||
void Message(ETcpSocket*);
|
||||
void Disconnected(ETcpSocket*);
|
||||
void Error(ETcpSocket*,QAbstractSocket::SocketError socketError);
|
||||
void HostFound(ETcpSocket*);
|
||||
void ProxyAuthenticationRequired(ETcpSocket*,const QNetworkProxy &proxy, QAuthenticator *authenticator);
|
||||
void StateChanged(ETcpSocket*,QAbstractSocket::SocketState socketState);
|
||||
//void Connected(QTcpSocket*);
|
||||
//void errorConnect(QTcpSocket*,QAbstractSocket::SocketError);
|
||||
};
|
||||
|
||||
#endif // CLIENT_H
|
68
sync/LocalScanner.cpp
Executable file
68
sync/LocalScanner.cpp
Executable file
@ -0,0 +1,68 @@
|
||||
#include "LocalScanner.h"
|
||||
#include "config.h"
|
||||
|
||||
LocalScanner::LocalScanner():
|
||||
QObject()
|
||||
{
|
||||
wiat.setInterval(1000);
|
||||
connect(&wiat,SIGNAL(timeout()),SLOT(scaned_()));
|
||||
}
|
||||
|
||||
void LocalScanner::clear(){
|
||||
results.clear();
|
||||
}
|
||||
|
||||
void LocalScanner::setInterval(int msec){
|
||||
wiat.setInterval(msec);
|
||||
}
|
||||
|
||||
void LocalScanner::clearSocets(){
|
||||
for(ETcpSocket* i:socets)
|
||||
delete i;
|
||||
socets.clear();
|
||||
}
|
||||
|
||||
QHostAddress LocalScanner::thisAdress(){
|
||||
QList<QHostAddress> adress= QNetworkInterface::allAddresses();
|
||||
for(QHostAddress &ip:adress)
|
||||
if(ip.protocol() == QAbstractSocket::IPv4Protocol && ip != QHostAddress(QHostAddress::LocalHost))
|
||||
return ip;
|
||||
return QHostAddress::LocalHost;
|
||||
}
|
||||
|
||||
void LocalScanner::scane(){
|
||||
if(!socets.empty())
|
||||
return ;
|
||||
QList<QHostAddress> adress= QNetworkInterface::allAddresses();
|
||||
clear();
|
||||
wiat.start();
|
||||
for(QHostAddress &ip:adress){
|
||||
if(ip.protocol() == QAbstractSocket::IPv4Protocol && ip != QHostAddress(QHostAddress::LocalHost)){
|
||||
for(int i=0;i<256;i++){
|
||||
QString adr= ip.toString();
|
||||
adr=adr.left(adr.lastIndexOf("."))+"."+QString::number(i);
|
||||
ETcpSocket *temp=new ETcpSocket;
|
||||
connect(temp,SIGNAL(Connected(ETcpSocket*)),SLOT(connected(ETcpSocket*)));
|
||||
temp->getSource()->connectToHost(adr,DEDAULT_PORT);
|
||||
socets.push_back(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LocalScanner::scaned_(){
|
||||
wiat.stop();
|
||||
emit scaned(&results);
|
||||
clearSocets();
|
||||
}
|
||||
|
||||
void LocalScanner::connected(ETcpSocket *c){
|
||||
results.push_back(c);
|
||||
}
|
||||
|
||||
LocalScanner::~LocalScanner(){
|
||||
for(ETcpSocket* i: socets)
|
||||
delete i;
|
||||
socets.clear();
|
||||
|
||||
}
|
29
sync/LocalScanner.h
Executable file
29
sync/LocalScanner.h
Executable file
@ -0,0 +1,29 @@
|
||||
#ifndef LocalServers_H
|
||||
#define LocalServers_H
|
||||
#include <QNetworkInterface>
|
||||
#include <QHostInfo>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include "ETcpSocket.h"
|
||||
|
||||
class LocalScanner:public QObject{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QList<ETcpSocket*> socets;
|
||||
QList<ETcpSocket*> results;
|
||||
QTimer wiat;
|
||||
void clear();
|
||||
void clearSocets();
|
||||
private slots:
|
||||
void scaned_();
|
||||
void connected(ETcpSocket *);
|
||||
public:
|
||||
void scane();
|
||||
void setInterval(int msec);
|
||||
static QHostAddress thisAdress();
|
||||
LocalScanner();
|
||||
~LocalScanner();
|
||||
signals:
|
||||
void scaned(QList<ETcpSocket*>*);
|
||||
};
|
||||
#endif // LocalServers_H
|
19
sync/config.h
Normal file
19
sync/config.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
// LIB VERSION
|
||||
#define MAJOR_VERSION 0
|
||||
#define MINOR_VERSION 0
|
||||
#define REVISION_VERSION 0
|
||||
|
||||
// sqlite config
|
||||
#define DATABASE_NAME "songdata.dat"
|
||||
#define DATATABLE_NAME "songs"
|
||||
|
||||
// network config
|
||||
#define DEDAULT_PORT 1239
|
||||
#define MAX_SYNC_TIME 20 * 1000 // 10 sec on microsec
|
||||
#define SYNC_TIME 5 * 1000 // 5 sec on microsec
|
||||
#define DEEP_SCANER_INTERVAL 10000 // 10 sec
|
||||
|
||||
#endif // CONFIG_H
|
58
sync/exaptions.h
Normal file
58
sync/exaptions.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef EXAPTIONS_H
|
||||
#define EXAPTIONS_H
|
||||
|
||||
#include <exception>
|
||||
#include <QString>
|
||||
#include <QTranslator>
|
||||
/**
|
||||
* @brief The MediaException class
|
||||
*/
|
||||
class MediaException:public std::exception
|
||||
{
|
||||
public:
|
||||
QString what(){
|
||||
return QObject::tr("Your operating system or platform has not supported media files.");
|
||||
}
|
||||
};
|
||||
|
||||
class AddNodeExaption:public std::exception
|
||||
{
|
||||
public:
|
||||
QString what(){
|
||||
return QObject::tr("Address not available");
|
||||
}
|
||||
};
|
||||
|
||||
class CreatePackageExaption:public std::exception
|
||||
{
|
||||
public:
|
||||
QString what(){
|
||||
return QObject::tr("Сould not generate network packet");
|
||||
}
|
||||
};
|
||||
|
||||
class BadAnswerExaption:public std::exception
|
||||
{
|
||||
public:
|
||||
QString what(){
|
||||
return QObject::tr("could not parse message nodes.");
|
||||
}
|
||||
};
|
||||
|
||||
class BrodcastConflict:public std::exception
|
||||
{
|
||||
public:
|
||||
QString what(){
|
||||
return QObject::tr("The server received the packet from the server.");
|
||||
}
|
||||
};
|
||||
|
||||
class SyncError:public std::exception
|
||||
{
|
||||
public:
|
||||
QString what(){
|
||||
return QObject::tr("The playlist is empty, the player has nothing to play.");
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXAPTIONS_H
|
210
sync/node.cpp
Normal file
210
sync/node.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
#include "node.h"
|
||||
#include <QTcpSocket>
|
||||
#include "song.h"
|
||||
#include <QDataStream>
|
||||
#include "exaptions.h"
|
||||
namespace syncLib{
|
||||
|
||||
package::package(){
|
||||
clear();
|
||||
}
|
||||
package::package(const 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_play){
|
||||
ret = ret && true;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_sync){
|
||||
ret = ret && (playdata.run > 0 && playdata.seek > 0);
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h){
|
||||
ret = ret && header.size > 0;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song){
|
||||
ret = ret && source.size > 0;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_close){
|
||||
ret = ret && true;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_stop){
|
||||
ret = ret && true;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void package::clear(){
|
||||
type = TypePackage::t_void;
|
||||
source.clear();
|
||||
playdata.run = 0;
|
||||
playdata.seek = 0;
|
||||
}
|
||||
|
||||
QByteArray package::parseTo(){
|
||||
QByteArray temp;
|
||||
QDataStream stream(temp);
|
||||
temp.clear();
|
||||
if(isValid()){
|
||||
stream << static_cast<unsigned char>(type);
|
||||
|
||||
if(type & TypePackage::t_sync){
|
||||
stream << playdata.run;
|
||||
stream << playdata.seek;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h){
|
||||
stream << header;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song){
|
||||
stream << source;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool package::parseFrom(const QByteArray &array){
|
||||
type = TypePackage::t_void;
|
||||
QDataStream stream(array);
|
||||
|
||||
unsigned char temp_type;
|
||||
stream >> temp_type;
|
||||
type = static_cast<TypePackage> (temp_type);
|
||||
|
||||
if(type & TypePackage::t_sync){
|
||||
stream >> playdata.run;
|
||||
stream >> playdata.seek;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h){
|
||||
stream >> header;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song){
|
||||
stream >> source;
|
||||
|
||||
}
|
||||
|
||||
return isValid();
|
||||
}
|
||||
|
||||
Node::Node():QTcpServer(){
|
||||
connect(this,SIGNAL(acceptError(QAbstractSocket::SocketError)),SLOT(acceptError_(QAbstractSocket::SocketError)));
|
||||
connect(this,SIGNAL(newConnection()),SLOT(newConnection_()));
|
||||
}
|
||||
|
||||
void Node::acceptError_(ETcpSocket*c){
|
||||
c->getSource()->close();
|
||||
clients.removeOne(c);
|
||||
emit ClientDisconnected(c);
|
||||
delete c;
|
||||
}
|
||||
|
||||
QList<ETcpSocket*>* Node::getClients(){
|
||||
return &clients;
|
||||
}
|
||||
|
||||
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*)));
|
||||
emit ClientConnected(newClient);
|
||||
}
|
||||
|
||||
void Node::readData(ETcpSocket *c){
|
||||
emit Message(c);
|
||||
}
|
||||
|
||||
void Node::WriteAll(const QByteArray &data){
|
||||
for(ETcpSocket*i:clients){
|
||||
i->getSource()->write(data);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::disconnectClient(ETcpSocket *c){
|
||||
c->getSource()->close();
|
||||
clients.removeOne(c);
|
||||
delete c;
|
||||
}
|
||||
|
||||
bool Node::addNode(const QString &node,int port){
|
||||
ETcpSocket *temp;
|
||||
|
||||
try{
|
||||
temp = new ETcpSocket(node,port);
|
||||
}catch(AddNodeExaption &e){
|
||||
#ifdef QT_DEBUG
|
||||
qDebug() << e.what();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
clients.push_back(temp);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Node::addNode(ETcpSocket *node){
|
||||
if(node->getSource()->isOpen()){
|
||||
clients.append(node);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Node::~Node(){
|
||||
for(ETcpSocket *i:clients){
|
||||
i->getSource()->close();
|
||||
delete i;
|
||||
}
|
||||
this->close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
107
sync/node.h
Normal file
107
sync/node.h
Normal file
@ -0,0 +1,107 @@
|
||||
#ifndef NODE_H
|
||||
#define NODE_H
|
||||
#include <QTcpServer>
|
||||
#include "ETcpSocket.h"
|
||||
#include <song.h>
|
||||
class Syncer;
|
||||
namespace syncLib {
|
||||
|
||||
typedef unsigned char Type;
|
||||
|
||||
/**
|
||||
* @brief The TypePackage enum
|
||||
* t_void - this package empty and not valid.
|
||||
* t_close - the information about close channel.
|
||||
* t_sync - the infomation about sync playning media file on network.
|
||||
* t_song - the package with this type is necessary for translite media data on network.
|
||||
* t_stop - the package with type 'stop' necessary for stoping playning media files.
|
||||
*/
|
||||
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
|
||||
* 4 byte - size of data of package (it avelable if type is t_sync or t_song)
|
||||
* data
|
||||
*/
|
||||
class package
|
||||
{
|
||||
/*parse map */
|
||||
|
||||
/*
|
||||
* 1 byle - type
|
||||
* 4 byte - size of data of package (it avelable if type is t_sync or t_song)
|
||||
* data
|
||||
*/
|
||||
|
||||
private:
|
||||
Type type;
|
||||
Song source;
|
||||
SongHeader header;
|
||||
Syncer playdata;
|
||||
public:
|
||||
package();
|
||||
package(const 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(const QByteArray& array);
|
||||
friend class Sync;
|
||||
};
|
||||
|
||||
class Node:public QTcpServer{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
QList<ETcpSocket*> clients;
|
||||
private slots:
|
||||
void acceptError_(ETcpSocket*);
|
||||
void newConnection_();
|
||||
void readData(ETcpSocket*_client);
|
||||
public:
|
||||
Node();
|
||||
void WriteAll(const QByteArray&);
|
||||
void disconnectClient(ETcpSocket*);
|
||||
QList<ETcpSocket*>* getClients();
|
||||
bool addNode(const QString &node, int port = DEDAULT_PORT);
|
||||
bool addNode(ETcpSocket* node);
|
||||
~Node();
|
||||
signals:
|
||||
void Error(QString);
|
||||
void Message(ETcpSocket*);
|
||||
void ClientDisconnected(ETcpSocket*);
|
||||
void ClientConnected(ETcpSocket*);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // NODE_H
|
81
sync/song.cpp
Normal file
81
sync/song.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include "song.h"
|
||||
|
||||
namespace syncLib{
|
||||
|
||||
SongHeader::SongHeader()
|
||||
{
|
||||
this->id = -1;
|
||||
this->name = "";
|
||||
this->size = 0;
|
||||
}
|
||||
|
||||
SongHeader& SongHeader::operator =(const SongHeader& right){
|
||||
this->id = right.id;
|
||||
this->name = right.name;
|
||||
this->size = right.size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool SongHeader::operator ==(const SongHeader& right){
|
||||
return this->name == right.name && this->size == right.size;
|
||||
}
|
||||
|
||||
unsigned int SongHeader::getSize() const{
|
||||
QByteArray size;
|
||||
QDataStream stream(size);
|
||||
stream << id << name << this->size;
|
||||
return size.size();
|
||||
}
|
||||
|
||||
Song::Song():
|
||||
SongHeader()
|
||||
{
|
||||
source.clear();
|
||||
}
|
||||
|
||||
QDataStream& operator << (QDataStream& stream, const SongHeader& song){
|
||||
stream << song.id;
|
||||
stream << song.name;
|
||||
stream << song.size;
|
||||
return stream;
|
||||
}
|
||||
QDataStream& operator >> (QDataStream& stream, SongHeader& song){
|
||||
stream >> song.id;
|
||||
stream >> song.name;
|
||||
stream >> song.size;
|
||||
return stream;
|
||||
}
|
||||
|
||||
Song::Song(const SongHeader& from)
|
||||
:Song::Song()
|
||||
{
|
||||
this->id = from.id;
|
||||
this->name = from.name;
|
||||
this->size = from.size;
|
||||
}
|
||||
|
||||
void Song::clear(){
|
||||
source.clear();
|
||||
}
|
||||
|
||||
Song::~Song(){
|
||||
source.clear();
|
||||
}
|
||||
|
||||
unsigned int Song::getSize() const{
|
||||
return SongHeader::getSize() + source.size();
|
||||
}
|
||||
|
||||
QDataStream& operator << (QDataStream& stream,const Song& song){
|
||||
stream << static_cast<const SongHeader&>(song);
|
||||
stream << song.source;
|
||||
return stream;
|
||||
}
|
||||
|
||||
QDataStream& operator >> (QDataStream& stream, Song& song){
|
||||
stream >> static_cast<SongHeader&>(song);
|
||||
stream >> song.source;
|
||||
return stream;
|
||||
}
|
||||
|
||||
}
|
66
sync/song.h
Normal file
66
sync/song.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef SONG_H
|
||||
#define SONG_H
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <QDataStream>
|
||||
#include <config.h>
|
||||
/**
|
||||
* @brief Time_point on nanosecunds (uint64_t)
|
||||
*/
|
||||
typedef quint64 milliseconds;
|
||||
|
||||
namespace syncLib {
|
||||
|
||||
/**
|
||||
* @brief The Syncer struct
|
||||
*
|
||||
*/
|
||||
struct Syncer
|
||||
{
|
||||
/**
|
||||
* @brief seek - wher is play media file
|
||||
*/
|
||||
milliseconds seek;
|
||||
/**
|
||||
* @brief run when is play media file (int)
|
||||
*/
|
||||
milliseconds run;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The SongHeader class sound header with media information
|
||||
* (id,size and name)
|
||||
*/
|
||||
class SongHeader
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
QString name;
|
||||
int size;
|
||||
SongHeader();
|
||||
SongHeader& operator = (const SongHeader& right);
|
||||
bool operator == (const SongHeader& right);
|
||||
virtual unsigned int getSize()const;
|
||||
virtual ~SongHeader();
|
||||
friend QDataStream& operator << (QDataStream& stream, const SongHeader& song);
|
||||
friend QDataStream& operator >> (QDataStream& stream, SongHeader& song);
|
||||
};
|
||||
/**
|
||||
* @brief The Song class
|
||||
* into this calss added mediadata of playable media file.
|
||||
*/
|
||||
class Song : public SongHeader{
|
||||
private:
|
||||
QByteArray source;
|
||||
public:
|
||||
Song();
|
||||
Song(const SongHeader& from);
|
||||
void clear();
|
||||
unsigned int getSize() const;
|
||||
~Song();
|
||||
friend QDataStream& operator << (QDataStream& stream, const Song& song);
|
||||
friend QDataStream& operator >> (QDataStream& stream, Song& song);
|
||||
friend class Sync;
|
||||
};
|
||||
}
|
||||
#endif // SONG_H
|
350
sync/sync.cpp
Normal file
350
sync/sync.cpp
Normal file
@ -0,0 +1,350 @@
|
||||
#include "sync.h"
|
||||
#include <QtSql>
|
||||
#include <QMultimedia>
|
||||
#include <QMediaPlayer>
|
||||
#include <QSqlQuery>
|
||||
#include "exaptions.h"
|
||||
#include "time.h"
|
||||
#include "thread"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
#include <QDebug>
|
||||
#endif
|
||||
|
||||
namespace syncLib{
|
||||
|
||||
Sync::Sync(){
|
||||
node = new Node();
|
||||
player = new QMediaPlayer(nullptr,QMediaPlayer::LowLatency);
|
||||
if(!player->isAvailable()){
|
||||
throw MediaException();
|
||||
}
|
||||
initDB();
|
||||
connect(node,SIGNAL(Message(ETcpSocket*)),SLOT(packageRender(ETcpSocket*)));
|
||||
connect(&deepScaner,SIGNAL(scaned(QList<ETcpSocket*>*)),SLOT(deepScaned(QList<ETcpSocket*>*)));
|
||||
|
||||
}
|
||||
|
||||
void Sync::initDB(){
|
||||
if(db) return;
|
||||
*db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
QDir d(QString("./%0").arg(DATABASE_NAME));
|
||||
db->setDatabaseName(d.absolutePath());
|
||||
if(db->open()){
|
||||
qyery = new QSqlQuery(*db);
|
||||
QString qyer = QString("CREATE TABLE IF NOT EXISTS %0 "
|
||||
"id int NOT NULL AUTO_INCREMENT,"
|
||||
"name VARCHAR(100),"
|
||||
"size INT NOT NULL,"
|
||||
"data BLOB NOT NULL").arg(DATATABLE_NAME);
|
||||
qyery->exec(qyer);
|
||||
}
|
||||
}
|
||||
|
||||
int Sync::save(const Song &song){
|
||||
QString qyer = QString("INSERT INTO %0 (name, size, data) VALUES"
|
||||
"(%1,%2, :data)").arg(DATATABLE_NAME,
|
||||
song.name,
|
||||
QString::number(song.size));
|
||||
qyery->prepare(qyer);
|
||||
qyery->bindValue(":data",song.source);
|
||||
if(!qyery->exec())
|
||||
return -1;
|
||||
if(qyery->exec(QString("SELECT MAAX(id) form %0").arg(DATATABLE_NAME)))
|
||||
return -1;
|
||||
return qyery->value(0).toInt();
|
||||
}
|
||||
|
||||
bool Sync::load(const SongHeader &song,Song &result){
|
||||
result.clear();
|
||||
if(song.id > -1){
|
||||
QString qyer = QString("SELECT * from %0 where id=%1").arg(DATATABLE_NAME).arg(song.id);
|
||||
if(!qyery->exec(qyer)){
|
||||
return false;
|
||||
}
|
||||
}else if(!song.name.isEmpty() && song.size > 0){
|
||||
QString qyer = QString("SELECT * from %0 where name=%1 and size=%2").arg(DATATABLE_NAME).arg(song.name).arg(song.size);
|
||||
if(!qyery->exec(qyer)){
|
||||
return false;
|
||||
}
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
|
||||
result.id = qyery->value(0).toInt();
|
||||
result.name = qyery->value(1).toString();
|
||||
result.size = qyery->value(2).toInt();
|
||||
result.source = qyery->value(3).toByteArray();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* information about chrono
|
||||
* https://stackoverflow.com/questions/31255486/c-how-do-i-convert-a-stdchronotime-point-to-long-and-back
|
||||
*/
|
||||
|
||||
milliseconds Sync::now(){
|
||||
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();
|
||||
}
|
||||
|
||||
Clock Sync::from(const milliseconds& mc){
|
||||
std::chrono::milliseconds dur(mc);
|
||||
return Clock(dur);
|
||||
}
|
||||
|
||||
bool Sync::play(const SongHeader &header, const Syncer *syncdata){
|
||||
QString qyer = QString("SELECT * from %0 where name=%1 and size=%2").arg(DATATABLE_NAME).arg(header.name).arg(header.size);
|
||||
if(!qyery->exec(qyer)){
|
||||
return false;
|
||||
}
|
||||
Song song;
|
||||
song.id = qyery->value(0).toInt();
|
||||
song.name = qyery->value(1).toString();
|
||||
song.size = qyery->value(2).toInt();
|
||||
song.source = qyery->value(3).toByteArray();
|
||||
return Sync::play(song,syncdata);
|
||||
}
|
||||
|
||||
bool Sync::play(Song &song, Syncer *syncdata){
|
||||
QBuffer buffer(&song.source);
|
||||
player->setMedia(QMediaContent(), &buffer);
|
||||
if(syncdata && !sync(*syncdata)){
|
||||
return false;
|
||||
}
|
||||
|
||||
fbroadcaster = !bool(syncdata);
|
||||
if(fbroadcaster){
|
||||
package pac;
|
||||
if(!createPackage(t_song_h | t_sync, pac)){
|
||||
throw CreatePackageExaption();
|
||||
}
|
||||
node->WriteAll(pac.parseTo());
|
||||
}
|
||||
|
||||
player->play();
|
||||
playList->push_front(static_cast<SongHeader>(song));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sync::play(int id_song, Syncer *syncdata){
|
||||
|
||||
QString qyer = QString("SELECT * from %0 where id=%1").arg(DATATABLE_NAME).arg(id_song);
|
||||
if(!qyery->exec(qyer)){
|
||||
return false;
|
||||
}
|
||||
Song song;
|
||||
song.id = qyery->value(0).toInt();
|
||||
song.name = qyery->value(1).toString();
|
||||
song.size = qyery->value(2).toInt();
|
||||
song.source = qyery->value(3).toByteArray();
|
||||
return Sync::play(song,syncdata);
|
||||
}
|
||||
|
||||
bool Sync::play(QString url){
|
||||
QFile f(url);
|
||||
if(!f.open(QIODevice::ReadOnly)){
|
||||
return false;
|
||||
}
|
||||
QByteArray bytes = f.readAll();
|
||||
f.close();
|
||||
QString name = url.right(url.lastIndexOf(QRegularExpression("[\\/]"))); // meby [[\\\/]]
|
||||
Song song;
|
||||
song.name = name;
|
||||
song.size = bytes.size();
|
||||
song.source = bytes;
|
||||
song.id = Sync::save(song);
|
||||
if(song.id < 0)
|
||||
return false;
|
||||
return Sync::play(song);
|
||||
}
|
||||
|
||||
void Sync::pause(){
|
||||
player->pause();
|
||||
}
|
||||
|
||||
void Sync::stop(){
|
||||
player->stop();
|
||||
}
|
||||
|
||||
void Sync::jump(const int seek){
|
||||
player->setPosition(seek);
|
||||
}
|
||||
|
||||
bool Sync::sync(const Syncer &sync){
|
||||
milliseconds sync_time = sync.run - now();
|
||||
if(sync_time > MAX_SYNC_TIME && sync_time <= 0)
|
||||
return false;
|
||||
Clock run_time = from(sync.run);
|
||||
do {
|
||||
std::this_thread::yield();
|
||||
} while (std::chrono::high_resolution_clock::now() < run_time);
|
||||
player->setPosition(sync.seek);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sync::createPackage(Type type, package &pac){
|
||||
pac.clear();
|
||||
|
||||
pac.type = type;
|
||||
|
||||
if(type & TypePackage::t_sync && fbroadcaster){
|
||||
|
||||
pac.playdata.run = now() + SYNC_TIME;
|
||||
pac.playdata.seek = player->position() + SYNC_TIME;
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song_h && fbroadcaster){
|
||||
if(playList->isEmpty())
|
||||
return false;
|
||||
|
||||
pac.header = playList->front();
|
||||
|
||||
}
|
||||
|
||||
if(type & TypePackage::t_song && fbroadcaster){
|
||||
if(playList->isEmpty())
|
||||
return false;
|
||||
|
||||
if(!load(playList->front(), pac.source))
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if(fbroadcaster)
|
||||
pac.type = TypePackage(pac.type | t_brodcaster);
|
||||
|
||||
return pac.isValid();
|
||||
}
|
||||
|
||||
void Sync::packageRender(ETcpSocket *socket){
|
||||
|
||||
QByteArray *array;
|
||||
while((array = socket->topStack())){
|
||||
package pkg;
|
||||
if(!pkg.parseFrom((*array))){
|
||||
throw BadAnswerExaption();
|
||||
continue;
|
||||
}
|
||||
// package answer;
|
||||
|
||||
// scaning servers
|
||||
|
||||
if(pkg.getType() & t_brodcaster && servers.indexOf(socket) == -1){
|
||||
servers.append(socket);
|
||||
}
|
||||
|
||||
if(!(pkg.getType() & t_brodcaster) && servers.indexOf(socket) != -1){
|
||||
servers.removeOne(socket);
|
||||
}
|
||||
|
||||
if(fbroadcaster == (pkg.getType() & t_brodcaster)){
|
||||
throw BrodcastConflict();
|
||||
return;
|
||||
}
|
||||
|
||||
if(pkg.getType() & t_brodcaster){
|
||||
|
||||
// if requst from server
|
||||
|
||||
if(pkg.getType() & t_play){
|
||||
player->play();
|
||||
}
|
||||
|
||||
if((pkg.getType() & t_song_h) && !play(pkg.getHeader(), &pkg.getPlayData())){
|
||||
if((pkg.getType() & t_song) && !play(pkg.getSong(), &pkg.getPlayData())){
|
||||
package answer;
|
||||
if(!createPackage(t_song | t_sync, answer)){
|
||||
throw CreatePackageExaption();
|
||||
}
|
||||
socket->Write(answer.parseTo());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(pkg.getType() & t_close){
|
||||
socket->getSource()->close();
|
||||
node->getClients()->removeOne(socket);
|
||||
delete socket;
|
||||
}
|
||||
|
||||
if(pkg.getType() & t_what){
|
||||
package answer;
|
||||
if(!createPackage(t_void, answer)){
|
||||
throw CreatePackageExaption();
|
||||
}
|
||||
socket->Write(answer.parseTo());
|
||||
}
|
||||
|
||||
if(pkg.getType() & t_sync){
|
||||
if(playList->empty()){
|
||||
throw SyncError();
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
package answer;
|
||||
if(!createPackage(pkg.getType() | ~t_what | ~t_play | ~t_stop | ~t_brodcaster, answer)){
|
||||
throw CreatePackageExaption();
|
||||
}
|
||||
socket->Write(answer.parseTo());
|
||||
|
||||
if(pkg.getType() & t_close){
|
||||
socket->getSource()->close();
|
||||
node->getClients()->removeOne(socket);
|
||||
delete socket;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
array->clear();
|
||||
delete array;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Sync::rescan(bool deep){
|
||||
package pac;
|
||||
if(!createPackage(t_what,pac)){
|
||||
throw CreatePackageExaption();
|
||||
return;
|
||||
}
|
||||
node->WriteAll(pac.parseTo());
|
||||
|
||||
if(deep){
|
||||
deepScaner.setInterval(DEEP_SCANER_INTERVAL);
|
||||
deepScaner.scane();
|
||||
}
|
||||
}
|
||||
|
||||
void Sync::deepScaned(QList<ETcpSocket *> * list){
|
||||
package pac;
|
||||
if(!createPackage(t_what,pac)){
|
||||
throw CreatePackageExaption();
|
||||
return;
|
||||
}
|
||||
QByteArray array = pac.parseTo();
|
||||
for(ETcpSocket * i: *list){
|
||||
i->Write(array);
|
||||
}
|
||||
}
|
||||
|
||||
Sync::~Sync(){
|
||||
delete node;
|
||||
delete db;
|
||||
delete player;
|
||||
servers.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
143
sync/sync.h
Normal file
143
sync/sync.h
Normal file
@ -0,0 +1,143 @@
|
||||
#ifndef SYNC_H
|
||||
#define SYNC_H
|
||||
#include "song.h"
|
||||
#include "node.h"
|
||||
#include "LocalScanner.h"
|
||||
#include <chrono>
|
||||
class QSqlDatabase;
|
||||
class QMediaPlayer;
|
||||
class QSqlQuery;
|
||||
namespace syncLib {
|
||||
|
||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> Clock;
|
||||
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* @brief The Sync class is main class of this library.
|
||||
* the 'sync' has supported synced playning media files on network and saving media data into local database.
|
||||
*/
|
||||
class Sync : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
Node *node;
|
||||
QSqlDatabase *db;
|
||||
QMediaPlayer *player;
|
||||
QList<SongHeader>* playList;
|
||||
QSqlQuery *qyery;
|
||||
QList<ETcpSocket*> servers;
|
||||
bool fbroadcaster;
|
||||
LocalScanner deepScaner;
|
||||
|
||||
|
||||
/**
|
||||
* @brief rescan - search for existing servers
|
||||
* result saved in servers
|
||||
*/
|
||||
void rescan(bool deep = false);
|
||||
/**
|
||||
* @brief initDB initialize local database of song
|
||||
*/
|
||||
void initDB();
|
||||
/**
|
||||
* @brief load song of database;
|
||||
* @brief song -
|
||||
* @brief result - the resulting value;
|
||||
* @return true if everything's done
|
||||
*/
|
||||
bool load(const SongHeader &song, Song &result);
|
||||
/**
|
||||
* @brief save media data into local database.
|
||||
* @param song savining media data.
|
||||
* @return id of song saved on local database.
|
||||
*/
|
||||
int save(const Song &song);
|
||||
/**
|
||||
* @brief fromDataBase return a song from local database by id.
|
||||
* @param id of song saved in local database.
|
||||
* @return song drom local database.
|
||||
*/
|
||||
Song fromDataBase(const int id);
|
||||
/**
|
||||
* @brief now - get now time on microsecunds
|
||||
* @return - count of microsecunds
|
||||
*/
|
||||
milliseconds now();
|
||||
/**
|
||||
* @brief from cast to chrono secunds
|
||||
* @param mcrs microseconds of uint_64
|
||||
* @return microseconds of chrono
|
||||
*/
|
||||
Clock from(const milliseconds &mcrs);
|
||||
/**
|
||||
* @brief createPackage - Create a package that shows current state of the node
|
||||
* @param type - Type of an answer
|
||||
* @param pac - the resulting value
|
||||
* @return true if everything's done
|
||||
*/
|
||||
bool createPackage(Type type ,package& pac);
|
||||
private slots:
|
||||
|
||||
/**
|
||||
* @brief packageRender - the handler of all messages received.
|
||||
* @param socket
|
||||
*/
|
||||
void packageRender(ETcpSocket* socket);
|
||||
/**
|
||||
* @brief deepScaned scaning in local network
|
||||
*/
|
||||
void deepScaned(QList<ETcpSocket *> *);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Play song in this device, if device has not supported playning media data this method throw MediaExcrption.
|
||||
* @param header of song
|
||||
* @param syncdata data of synbced playning of media data.
|
||||
* @return true if all done else false.
|
||||
*/
|
||||
bool play(const SongHeader &header, const Syncer *syncdata = nullptr);
|
||||
/**
|
||||
* @brief Play song in this device, if device has not supported playning media data this method throw MediaExcrption.
|
||||
* @param song playning media data.
|
||||
* @param syncdata data of synbced playning of media data.
|
||||
* @return true if all done else false.
|
||||
*/
|
||||
bool play(Song &song, Syncer *syncdata = nullptr);
|
||||
/**
|
||||
* @brief Play song from local media file.
|
||||
* @param url of local media file.
|
||||
* @return true if all done else false.
|
||||
*/
|
||||
bool play(QString url);
|
||||
/**
|
||||
* @brief Play song from local database by id.
|
||||
* @param id_song of song.
|
||||
* @return true if all done else false.
|
||||
*/
|
||||
bool play(int id_song, Syncer* syncdata = nullptr);
|
||||
/**
|
||||
* @brief Pause playning song.
|
||||
*/
|
||||
void pause();
|
||||
/**
|
||||
* @brief stop playning song.
|
||||
*/
|
||||
void stop();
|
||||
/**
|
||||
* @brief jump - jump to new position of playning media data.
|
||||
* @param seek - a new position of media data.
|
||||
*/
|
||||
void jump(const int seek);
|
||||
/**
|
||||
* @brief sync with server
|
||||
* @param sync - data of sync
|
||||
*/
|
||||
bool sync(const Syncer& sync);
|
||||
Sync();
|
||||
~Sync();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // SYNC_H
|
44
sync/sync.pro
Normal file
44
sync/sync.pro
Normal file
@ -0,0 +1,44 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2017-10-28T16:29:39
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += network multimedia sql
|
||||
|
||||
QT -= gui
|
||||
|
||||
TARGET = sync
|
||||
TEMPLATE = lib
|
||||
CONFIG += staticlib
|
||||
|
||||
# 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
|
||||
|
||||
SOURCES += \
|
||||
sync.cpp \
|
||||
song.cpp \
|
||||
node.cpp \
|
||||
ETcpSocket.cpp \
|
||||
LocalScanner.cpp
|
||||
|
||||
HEADERS += \
|
||||
sync.h \
|
||||
song.h \
|
||||
node.h \
|
||||
config.h \
|
||||
exaptions.h \
|
||||
ETcpSocket.h \
|
||||
LocalScanner.h
|
||||
unix {
|
||||
target.path = /usr/lib
|
||||
INSTALLS += target
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user