mirror of
https://github.com/QuasarApp/SoundBand.git
synced 2025-05-08 13:09:33 +00:00
added a create package method
This commit is contained in:
parent
c732a3d8bc
commit
285f068358
@ -70,7 +70,7 @@ void ETcpSocket::readReady_(){
|
||||
{
|
||||
array->remove(0,sizeof(qint32));
|
||||
ReadyStack.push_back(array);
|
||||
array=new QByteArray;
|
||||
array=new QByteArray();
|
||||
emit Message(this);
|
||||
}else{
|
||||
emit donwload(array->size(),size);
|
||||
@ -93,8 +93,9 @@ QTcpSocket* ETcpSocket::getSource()const{
|
||||
}
|
||||
|
||||
void ETcpSocket::nextItem(){
|
||||
if(ReadyStack.size())
|
||||
if( ReadyStack.size()){
|
||||
ReadyStack.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
int ETcpSocket::sizeDescriptPackege(){
|
||||
|
@ -4,6 +4,27 @@
|
||||
#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
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
// network config
|
||||
#define DEDAULT_PORT 1239
|
||||
#define MAX_SYNC_TIME 10 * 1000 * 1000 // 10 sec on microsec
|
||||
#define MAX_SYNC_TIME 20 * 1000 // 10 sec on microsec
|
||||
#define SYNC_TIME 5 * 1000 // 5 sec on microsec
|
||||
|
||||
#endif // CONFIG_H
|
||||
|
@ -6,11 +6,7 @@
|
||||
namespace syncLib{
|
||||
|
||||
package::package(){
|
||||
type = package::t_void;
|
||||
source.clear();
|
||||
playdata.run = 0;
|
||||
playdata.seek = 0;
|
||||
size = 0;
|
||||
clear();
|
||||
}
|
||||
package::package(const QByteArray &array):
|
||||
package::package(){
|
||||
@ -24,42 +20,51 @@ Syncer package::getPlayData() const{
|
||||
return playdata;
|
||||
}
|
||||
|
||||
package::TypePackage package::getType() const{
|
||||
TypePackage package::getType() const{
|
||||
return type;
|
||||
}
|
||||
|
||||
bool package::isValid() const{
|
||||
switch (type) {
|
||||
case package::t_void:
|
||||
case TypePackage::t_void:
|
||||
return false;
|
||||
case package::t_close:
|
||||
case TypePackage::t_close:
|
||||
return true;
|
||||
case package::t_sync:
|
||||
case TypePackage::t_sync:
|
||||
return playdata.run > 0 && playdata.seek > 0;
|
||||
case package::t_song:
|
||||
case TypePackage::t_song:
|
||||
return source.size > 0;
|
||||
case package::t_stop:
|
||||
case TypePackage::t_song_h:
|
||||
return header.size > 0;
|
||||
case TypePackage::t_stop:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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()){
|
||||
switch (type) {
|
||||
case package::t_void:
|
||||
case TypePackage::t_void:
|
||||
break;
|
||||
case package::t_close:
|
||||
case TypePackage::t_close:
|
||||
stream << int();
|
||||
stream << (unsigned char)(type);
|
||||
stream.device()->seek(0);
|
||||
stream << temp.size();
|
||||
break;
|
||||
case package::t_sync:
|
||||
case TypePackage::t_sync:
|
||||
stream << int();
|
||||
stream << (unsigned char)(type);
|
||||
stream << playdata.run;
|
||||
@ -67,14 +72,21 @@ QByteArray package::parseTo(){
|
||||
stream.device()->seek(0);
|
||||
stream << temp.size();
|
||||
break;
|
||||
case package::t_song:
|
||||
case TypePackage::t_song:
|
||||
stream << int();
|
||||
stream << (unsigned char)(type);
|
||||
stream << source;
|
||||
stream.device()->seek(0);
|
||||
stream << temp.size();
|
||||
break;
|
||||
case package::t_stop:
|
||||
case TypePackage::t_song_h:
|
||||
stream << int();
|
||||
stream << (unsigned char)(type);
|
||||
stream << header;
|
||||
stream.device()->seek(0);
|
||||
stream << temp.size();
|
||||
break;
|
||||
case TypePackage::t_stop:
|
||||
stream << int();
|
||||
stream << (unsigned char)(type);
|
||||
stream.device()->seek(0);
|
||||
@ -88,21 +100,24 @@ QByteArray package::parseTo(){
|
||||
}
|
||||
|
||||
bool package::parseFrom(const QByteArray &array){
|
||||
type = t_void;
|
||||
type = TypePackage::t_void;
|
||||
QDataStream stream(array);
|
||||
switch (type) {
|
||||
case package::t_void:
|
||||
case TypePackage::t_void:
|
||||
return false;
|
||||
case package::t_close:
|
||||
case TypePackage::t_close:
|
||||
return true;
|
||||
case package::t_sync:
|
||||
case TypePackage::t_sync:
|
||||
stream >> playdata.run;
|
||||
stream >> playdata.seek;
|
||||
return isValid();
|
||||
case package::t_song:
|
||||
case TypePackage::t_song:
|
||||
stream >> source;
|
||||
return isValid();
|
||||
case package::t_stop:
|
||||
case TypePackage::t_song_h:
|
||||
stream >> header;
|
||||
return isValid();
|
||||
case TypePackage::t_stop:
|
||||
return true;
|
||||
default:
|
||||
return isValid();
|
||||
|
37
sync/node.h
37
sync/node.h
@ -6,6 +6,23 @@
|
||||
class Syncer;
|
||||
namespace syncLib {
|
||||
|
||||
/**
|
||||
* @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 = 0x0,
|
||||
t_close = 0x1,
|
||||
t_sync = 0x2,
|
||||
t_song_h = 0x4,
|
||||
t_song = 0x8,
|
||||
t_stop = 0x10
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The package class. Package for translite media data on network
|
||||
*
|
||||
@ -23,25 +40,11 @@ class package
|
||||
* 4 byte - size of data of package (it avelable if type is t_sync or t_song)
|
||||
* data
|
||||
*/
|
||||
/**
|
||||
* @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 = 0x0,
|
||||
t_close = 0x1,
|
||||
t_sync = 0x2,
|
||||
t_song = 0x4,
|
||||
t_stop = 0x8
|
||||
};
|
||||
|
||||
private:
|
||||
TypePackage type;
|
||||
unsigned int size;
|
||||
Song source;
|
||||
SongHeader header;
|
||||
Syncer playdata;
|
||||
public:
|
||||
package();
|
||||
@ -59,8 +62,10 @@ public:
|
||||
Syncer getPlayData() const;
|
||||
TypePackage getType() const;
|
||||
bool isValid() const;
|
||||
void clear();
|
||||
QByteArray parseTo();
|
||||
bool parseFrom(const QByteArray& array);
|
||||
friend class Sync;
|
||||
};
|
||||
|
||||
class Node:public QTcpServer{
|
||||
|
@ -4,7 +4,7 @@ namespace syncLib{
|
||||
|
||||
SongHeader::SongHeader()
|
||||
{
|
||||
this->id = 0;
|
||||
this->id = -1;
|
||||
this->name = "";
|
||||
this->size = 0;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
/**
|
||||
* @brief Time_point on nanosecunds (uint64_t)
|
||||
*/
|
||||
typedef quint64 microseconds;
|
||||
typedef quint64 milliseconds;
|
||||
|
||||
namespace syncLib {
|
||||
|
||||
@ -20,11 +20,11 @@ struct Syncer
|
||||
/**
|
||||
* @brief seek - wher is play media file
|
||||
*/
|
||||
unsigned int seek;
|
||||
milliseconds seek;
|
||||
/**
|
||||
* @brief run when is play media file (int)
|
||||
*/
|
||||
microseconds run;
|
||||
milliseconds run;
|
||||
};
|
||||
|
||||
/**
|
||||
|
114
sync/sync.cpp
114
sync/sync.cpp
@ -3,8 +3,6 @@
|
||||
#include <QMultimedia>
|
||||
#include <QMediaPlayer>
|
||||
#include <QSqlQuery>
|
||||
#include "song.h"
|
||||
#include "node.h"
|
||||
#include "exaptions.h"
|
||||
#include "time.h"
|
||||
#include "thread"
|
||||
@ -55,14 +53,37 @@ int Sync::save(const Song &song){
|
||||
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
|
||||
*/
|
||||
|
||||
microseconds Sync::now(){
|
||||
milliseconds Sync::now(){
|
||||
auto tim = std::chrono::system_clock::now();
|
||||
auto mc = std::chrono::time_point_cast<std::chrono::microseconds>(tim);
|
||||
auto mc = std::chrono::time_point_cast<std::chrono::milliseconds>(tim);
|
||||
auto epoh = mc.time_since_epoch();
|
||||
#ifdef QT_DEBUG
|
||||
qDebug() << epoh.count();
|
||||
@ -70,29 +91,37 @@ microseconds Sync::now(){
|
||||
return epoh.count();
|
||||
}
|
||||
|
||||
Clock Sync::from(const microseconds& mc){
|
||||
std::chrono::duration<long> dur(mc);
|
||||
Clock Sync::from(const milliseconds& mc){
|
||||
std::chrono::milliseconds dur(mc);
|
||||
return Clock(dur);
|
||||
}
|
||||
|
||||
bool Sync::Play(SongHeader &header, 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){
|
||||
microseconds sync_time = syncdata->run - now();
|
||||
if(sync_time > MAX_SYNC_TIME && sync_time <= 0)
|
||||
return false;
|
||||
Clock run_time = from(syncdata->run);
|
||||
do {
|
||||
std::this_thread::yield();
|
||||
} while (std::chrono::high_resolution_clock::now() < run_time);
|
||||
player->setPosition(syncdata->seek);
|
||||
if(syncdata && !sync(*syncdata)){
|
||||
return false;
|
||||
}
|
||||
fbroadcaster = !bool(syncdata);
|
||||
player->play();
|
||||
playList->push_front(static_cast<SongHeader>(song));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sync::Play(int id_song){
|
||||
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)){
|
||||
@ -103,7 +132,7 @@ bool Sync::Play(int id_song){
|
||||
song.name = qyery->value(1).toString();
|
||||
song.size = qyery->value(2).toInt();
|
||||
song.source = qyery->value(3).toByteArray();
|
||||
return Sync::Play(song);
|
||||
return Sync::Play(song,syncdata);
|
||||
}
|
||||
|
||||
bool Sync::Play(QString url){
|
||||
@ -136,6 +165,56 @@ 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(TypePackage type, package &pac){
|
||||
pac.clear();
|
||||
|
||||
if(type & TypePackage::t_close){
|
||||
pac.type = type;
|
||||
|
||||
}else if(type & TypePackage::t_sync){
|
||||
if(!fbroadcaster)
|
||||
return false;
|
||||
|
||||
pac.type = type;
|
||||
pac.playdata.run = now() + SYNC_TIME;
|
||||
pac.playdata.seek = player->position() + SYNC_TIME;
|
||||
|
||||
}else if(type & TypePackage::t_song_h){
|
||||
if(!fbroadcaster || playList->isEmpty())
|
||||
return false;
|
||||
|
||||
pac.type = type;
|
||||
pac.header = playList->front();
|
||||
|
||||
}else if(type & TypePackage::t_song){
|
||||
if(!fbroadcaster || playList->isEmpty())
|
||||
return false;
|
||||
|
||||
pac.type = type;
|
||||
if(!load(playList->front(), pac.source))
|
||||
return false;
|
||||
|
||||
}else if(type & TypePackage::t_stop){
|
||||
pac.type = type;
|
||||
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
return pac.isValid();
|
||||
}
|
||||
|
||||
Sync::~Sync(){
|
||||
delete node;
|
||||
delete db;
|
||||
@ -144,3 +223,4 @@ Sync::~Sync(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
35
sync/sync.h
35
sync/sync.h
@ -1,6 +1,7 @@
|
||||
#ifndef SYNC_H
|
||||
#define SYNC_H
|
||||
#include "song.h"
|
||||
#include "node.h"
|
||||
#include <chrono>
|
||||
class QSqlDatabase;
|
||||
class QMediaPlayer;
|
||||
@ -21,11 +22,20 @@ private:
|
||||
Node *node;
|
||||
QSqlDatabase *db;
|
||||
QMediaPlayer *player;
|
||||
QList<SongHeader>* playList;
|
||||
QSqlQuery *qyery;
|
||||
bool fbroadcaster;
|
||||
/**
|
||||
* @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.
|
||||
@ -42,14 +52,28 @@ private:
|
||||
* @brief now - get now time on microsecunds
|
||||
* @return - count of microsecunds
|
||||
*/
|
||||
microseconds now();
|
||||
milliseconds now();
|
||||
/**
|
||||
* @brief from cast to chrono secunds
|
||||
* @param mcrs microseconds of uint_64
|
||||
* @return microseconds of chrono
|
||||
*/
|
||||
Clock from(const microseconds &mcrs);
|
||||
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(TypePackage type ,package& pac);
|
||||
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(SongHeader &header, 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.
|
||||
@ -68,7 +92,7 @@ public:
|
||||
* @param id_song of song.
|
||||
* @return true if all done else false.
|
||||
*/
|
||||
bool Play(int id_song);
|
||||
bool Play(int id_song, Syncer* syncdata = nullptr);
|
||||
/**
|
||||
* @brief Pause playning song.
|
||||
*/
|
||||
@ -82,6 +106,11 @@ public:
|
||||
* @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();
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user