move message dir into common

This commit is contained in:
badaix 2018-03-16 00:19:52 +01:00
parent 3f16a6ce88
commit 54a8ca824f
23 changed files with 14 additions and 12 deletions

View file

@ -1 +1,2 @@
add_library(common STATIC daemon.cpp sampleFormat.cpp)
add_library(common STATIC daemon.cpp sampleFormat.cpp)
add_subdirectory(message)

View file

@ -0,0 +1 @@
add_library(message STATIC pcmChunk.cpp)

View file

@ -0,0 +1,71 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef CODEC_HEADER_MESSAGE_H
#define CODEC_HEADER_MESSAGE_H
#include "message.h"
namespace msg
{
/**
* Codec dependend header of encoded data stream
*/
class CodecHeader : public BaseMessage
{
public:
CodecHeader(const std::string& codecName = "", size_t size = 0) : BaseMessage(message_type::kCodecHeader), payloadSize(size), codec(codecName)
{
payload = (char*)malloc(size);
}
virtual ~CodecHeader()
{
free(payload);
}
virtual void read(std::istream& stream)
{
readVal(stream, codec);
readVal(stream, &payload, payloadSize);
}
virtual uint32_t getSize() const
{
return sizeof(uint32_t) + codec.size() + sizeof(uint32_t) + payloadSize;
}
uint32_t payloadSize;
char* payload;
std::string codec;
protected:
virtual void doserialize(std::ostream& stream) const
{
writeVal(stream, codec);
writeVal(stream, payload, payloadSize);
}
};
}
#endif

117
common/message/hello.h Normal file
View file

@ -0,0 +1,117 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef HELLO_MSG_H
#define HELLO_MSG_H
#include "jsonMessage.h"
#include "common/utils.h"
#include "common/strCompat.h"
#include <string>
namespace msg
{
class Hello : public JsonMessage
{
public:
Hello() : JsonMessage(message_type::kHello)
{
}
Hello(const std::string& macAddress, const std::string& id, size_t instance) : JsonMessage(message_type::kHello)
{
msg["MAC"] = macAddress;
msg["HostName"] = ::getHostName();
msg["Version"] = VERSION;
msg["ClientName"] = "Snapclient";
msg["OS"] = ::getOS();
msg["Arch"] = ::getArch();
msg["Instance"] = instance;
msg["ID"] = id;
msg["SnapStreamProtocolVersion"] = 2;
}
virtual ~Hello()
{
}
std::string getMacAddress() const
{
return msg["MAC"];
}
std::string getHostName() const
{
return msg["HostName"];
}
std::string getVersion() const
{
return msg["Version"];
}
std::string getClientName() const
{
return msg["ClientName"];
}
std::string getOS() const
{
return msg["OS"];
}
std::string getArch() const
{
return msg["Arch"];
}
int getInstance() const
{
return get("Instance", 1);
}
int getProtocolVersion() const
{
return get("SnapStreamProtocolVersion", 1);
}
std::string getId() const
{
return get("ID", getMacAddress());
}
std::string getUniqueId() const
{
std::string id = getId();
int instance = getInstance();
if (instance != 1)
{
id = id + "#" + cpt::to_string(instance);
}
return id;
}
};
}
#endif

View file

@ -0,0 +1,85 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef JSON_MESSAGE_H
#define JSON_MESSAGE_H
#include "message.h"
#include "common/json.hpp"
using json = nlohmann::json;
namespace msg
{
class JsonMessage : public BaseMessage
{
public:
JsonMessage(message_type msgType) : BaseMessage(msgType)
{
}
virtual ~JsonMessage()
{
}
virtual void read(std::istream& stream)
{
std::string s;
readVal(stream, s);
msg = json::parse(s);
}
virtual uint32_t getSize() const
{
return sizeof(uint32_t) + msg.dump().size();
}
json msg;
protected:
virtual void doserialize(std::ostream& stream) const
{
writeVal(stream, msg.dump());
}
template<typename T>
T get(const std::string& what, const T& def) const
{
try
{
if (!msg.count(what))
return def;
return msg[what].get<T>();
}
catch(...)
{
return def;
}
}
};
}
#endif

314
common/message/message.h Normal file
View file

@ -0,0 +1,314 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef MESSAGE_H
#define MESSAGE_H
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <streambuf>
#include <vector>
#include <sys/time.h>
#include "common/endian.hpp"
#include "common/timeDefs.h"
template<typename CharT, typename TraitsT = std::char_traits<CharT> >
class vectorwrapbuf : public std::basic_streambuf<CharT, TraitsT>
{
public:
vectorwrapbuf(std::vector<CharT> &vec)
{
this->setg(vec.data(), vec.data(), vec.data() + vec.size());
}
};
struct membuf : public std::basic_streambuf<char>
{
membuf(char* begin, char* end)
{
this->setg(begin, begin, end);
}
};
enum message_type
{
kBase = 0,
kCodecHeader = 1,
kWireChunk = 2,
kServerSettings = 3,
kTime = 4,
kHello = 5,
kStreamTags = 6,
kFirst = kBase,
kLast = kStreamTags
};
struct tv
{
tv()
{
timeval t;
chronos::systemtimeofday(&t);
sec = t.tv_sec;
usec = t.tv_usec;
}
tv(timeval tv) : sec(tv.tv_sec), usec(tv.tv_usec) {};
tv(int32_t _sec, int32_t _usec) : sec(_sec), usec(_usec) {};
int32_t sec;
int32_t usec;
tv operator+(const tv& other) const
{
tv result(*this);
result.sec += other.sec;
result.usec += other.usec;
if (result.usec > 1000000)
{
result.sec += result.usec / 1000000;
result.usec %= 1000000;
}
return result;
}
tv operator-(const tv& other) const
{
tv result(*this);
result.sec -= other.sec;
result.usec -= other.usec;
while (result.usec < 0)
{
result.sec -= 1;
result.usec += 1000000;
}
return result;
}
};
namespace msg
{
const size_t max_size = 1000000;
struct BaseMessage;
using message_ptr = std::shared_ptr<msg::BaseMessage>;
struct BaseMessage
{
BaseMessage() : type(kBase), id(0), refersTo(0)
{
}
BaseMessage(message_type type_) : type(type_), id(0), refersTo(0)
{
}
virtual ~BaseMessage()
{
}
virtual void read(std::istream& stream)
{
readVal(stream, type);
readVal(stream, id);
readVal(stream, refersTo);
readVal(stream, sent.sec);
readVal(stream, sent.usec);
readVal(stream, received.sec);
readVal(stream, received.usec);
readVal(stream, size);
}
void deserialize(char* payload)
{
membuf databuf(payload, payload + BaseMessage::getSize());
std::istream is(&databuf);
read(is);
}
void deserialize(const BaseMessage& baseMessage, char* payload)
{
type = baseMessage.type;
id = baseMessage.id;
refersTo = baseMessage.refersTo;
sent = baseMessage.sent;
received = baseMessage.received;
size = baseMessage.size;
membuf databuf(payload, payload + size);
std::istream is(&databuf);
read(is);
}
virtual void serialize(std::ostream& stream) const
{
writeVal(stream, type);
writeVal(stream, id);
writeVal(stream, refersTo);
writeVal(stream, sent.sec);
writeVal(stream, sent.usec);
writeVal(stream, received.sec);
writeVal(stream, received.usec);
size = getSize();
writeVal(stream, size);
doserialize(stream);
}
virtual uint32_t getSize() const
{
return 3*sizeof(uint16_t) + 2*sizeof(tv) + sizeof(uint32_t);
};
uint16_t type;
mutable uint16_t id;
uint16_t refersTo;
tv received;
mutable tv sent;
mutable uint32_t size;
protected:
void writeVal(std::ostream& stream, const bool& val) const
{
char c = val?1:0;
writeVal(stream, c);
}
void writeVal(std::ostream& stream, const char& val) const
{
stream.write(reinterpret_cast<const char*>(&val), sizeof(char));
}
void writeVal(std::ostream& stream, const uint16_t& val) const
{
uint16_t v = SWAP_16(val);
stream.write(reinterpret_cast<const char*>(&v), sizeof(uint16_t));
}
void writeVal(std::ostream& stream, const int16_t& val) const
{
uint16_t v = SWAP_16(val);
stream.write(reinterpret_cast<const char*>(&v), sizeof(int16_t));
}
void writeVal(std::ostream& stream, const uint32_t& val) const
{
uint32_t v = SWAP_32(val);
stream.write(reinterpret_cast<const char*>(&v), sizeof(uint32_t));
}
void writeVal(std::ostream& stream, const int32_t& val) const
{
uint32_t v = SWAP_32(val);
stream.write(reinterpret_cast<const char*>(&v), sizeof(int32_t));
}
void writeVal(std::ostream& stream, const char* payload, const uint32_t& size) const
{
writeVal(stream, size);
stream.write(payload, size);
}
void writeVal(std::ostream& stream, const std::string& val) const
{
uint32_t size = val.size();
writeVal(stream, val.c_str(), size);
}
void readVal(std::istream& stream, bool& val) const
{
char c;
readVal(stream, c);
val = (c != 0);
}
void readVal(std::istream& stream, char& val) const
{
stream.read(reinterpret_cast<char*>(&val), sizeof(char));
}
void readVal(std::istream& stream, uint16_t& val) const
{
stream.read(reinterpret_cast<char*>(&val), sizeof(uint16_t));
val = SWAP_16(val);
}
void readVal(std::istream& stream, int16_t& val) const
{
stream.read(reinterpret_cast<char*>(&val), sizeof(int16_t));
val = SWAP_16(val);
}
void readVal(std::istream& stream, uint32_t& val) const
{
stream.read(reinterpret_cast<char*>(&val), sizeof(uint32_t));
val = SWAP_32(val);
}
void readVal(std::istream& stream, int32_t& val) const
{
stream.read(reinterpret_cast<char*>(&val), sizeof(int32_t));
val = SWAP_32(val);
}
void readVal(std::istream& stream, char** payload, uint32_t& size) const
{
readVal(stream, size);
*payload = (char*)realloc(*payload, size);
stream.read(*payload, size);
}
void readVal(std::istream& stream, std::string& val) const
{
uint32_t size;
readVal(stream, size);
val.resize(size);
stream.read(&val[0], size);
}
virtual void doserialize(std::ostream& stream) const
{
};
};
struct SerializedMessage
{
~SerializedMessage()
{
free(buffer);
}
BaseMessage message;
char* buffer;
};
}
#endif

View file

@ -0,0 +1,83 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include <string.h>
#include <iostream>
#include "pcmChunk.h"
#include "aixlog.hpp"
using namespace std;
namespace msg
{
PcmChunk::PcmChunk(const SampleFormat& sampleFormat, size_t ms) : WireChunk(sampleFormat.rate*sampleFormat.frameSize*ms / 1000), format(sampleFormat), idx_(0)
{
}
PcmChunk::PcmChunk(const PcmChunk& pcmChunk) : WireChunk(pcmChunk), format(pcmChunk.format), idx_(0)
{
}
PcmChunk::PcmChunk() : WireChunk(), idx_(0)
{
}
PcmChunk::~PcmChunk()
{
}
int PcmChunk::seek(int frames)
{
if ((frames < 0) && (-frames > (int)idx_))
frames = -idx_;
idx_ += frames;
if (idx_ > getFrameCount())
idx_ = getFrameCount();
return idx_;
}
int PcmChunk::readFrames(void* outputBuffer, size_t frameCount)
{
//logd << "read: " << frameCount << ", total: " << (wireChunk->length / format.frameSize) << ", idx: " << idx;// << std::endl;
int result = frameCount;
if (idx_ + frameCount > (payloadSize / format.frameSize))
result = (payloadSize / format.frameSize) - idx_;
//logd << ", from: " << format.frameSize*idx << ", to: " << format.frameSize*idx + format.frameSize*result;
if (outputBuffer != NULL)
memcpy((char*)outputBuffer, (char*)(payload) + format.frameSize*idx_, format.frameSize*result);
idx_ += result;
//logd << ", new idx: " << idx << ", result: " << result << ", wireChunk->length: " << wireChunk->length << ", format.frameSize: " << format.frameSize << "\n";//std::endl;
return result;
}
}

98
common/message/pcmChunk.h Normal file
View file

@ -0,0 +1,98 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef PCM_CHUNK_H
#define PCM_CHUNK_H
#include <chrono>
#include "message.h"
#include "wireChunk.h"
#include "common/sampleFormat.h"
namespace msg
{
/**
* Piece of PCM data with SampleFormat information
* Has information about "when" recorded (start) and duration
* frames can be read with "readFrames", which will also change the start time
*/
class PcmChunk : public WireChunk
{
public:
PcmChunk(const SampleFormat& sampleFormat, size_t ms);
PcmChunk(const PcmChunk& pcmChunk);
PcmChunk();
virtual ~PcmChunk();
int readFrames(void* outputBuffer, size_t frameCount);
int seek(int frames);
virtual chronos::time_point_clk start() const
{
return chronos::time_point_clk(
chronos::sec(timestamp.sec) +
chronos::usec(timestamp.usec) +
chronos::usec((chronos::usec::rep)(1000000. * ((double)idx_ / (double)format.rate)))
);
}
inline chronos::time_point_clk end() const
{
return start() + durationLeft<chronos::usec>();
}
template<typename T>
inline T duration() const
{
return std::chrono::duration_cast<T>(chronos::nsec((chronos::nsec::rep)(1000000 * getFrameCount() / format.msRate())));
}
template<typename T>
inline T durationLeft() const
{
return std::chrono::duration_cast<T>(chronos::nsec((chronos::nsec::rep)(1000000 * (getFrameCount() - idx_) / format.msRate())));
}
inline bool isEndOfChunk() const
{
return idx_ >= getFrameCount();
}
inline size_t getFrameCount() const
{
return (payloadSize / format.frameSize);
}
inline size_t getSampleCount() const
{
return (payloadSize / format.sampleSize);
}
SampleFormat format;
private:
uint32_t idx_;
};
}
#endif

View file

@ -0,0 +1,91 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef SERVER_SETTINGS_H
#define SERVER_SETTINGS_H
#include "jsonMessage.h"
namespace msg
{
class ServerSettings : public JsonMessage
{
public:
ServerSettings() : JsonMessage(message_type::kServerSettings)
{
setBufferMs(0);
setLatency(0);
setVolume(100);
setMuted(false);
}
virtual ~ServerSettings()
{
}
int32_t getBufferMs()
{
return get("bufferMs", 0);
}
int32_t getLatency()
{
return get("latency", 0);
}
uint16_t getVolume()
{
return get("volume", 100);
}
bool isMuted()
{
return get("muted", false);
}
void setBufferMs(int32_t bufferMs)
{
msg["bufferMs"] = bufferMs;
}
void setLatency(int32_t latency)
{
msg["latency"] = latency;
}
void setVolume(uint16_t volume)
{
msg["volume"] = volume;
}
void setMuted(bool muted)
{
msg["muted"] = muted;
}
};
}
#endif

View file

@ -0,0 +1,78 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef STREAMTAGS_H
#define STREAMTAGS_H
#include "jsonMessage.h"
/*
* Due to the PCM pipe implementation of snapcast input we cannot know track start/end
* it's all a long stream (although we detect idle situations)
*
* So, we cannot push metadata on start of track as we don't know when that is.
*
* I.E. we push metadata as we get an update, as we don't know when an update
* is complete (different meta supported in different stream interfaces)
* it is the streamreaders responsibility to update metadata and
* trigger a client notification.
*
* I.E. we need to suppply the client notification mechanism.
*/
namespace msg
{
class StreamTags : public JsonMessage
{
public:
/*
Usage:
json jtag = {
{"artist", "Pink Floyd"},
{"album", "Dark Side of the Moon"},
{"track", "Money"},
{"spotifyid", "akjhasi7wehke7698"},
{"musicbrainzid", "akjhasi7wehke7698"},
};
this->meta_.reset(new msg::StreamTags(jtag));
Stream input can decide on tags, IDK... but smart
to use some common naming scheme
*/
StreamTags(json j) : JsonMessage(message_type::kStreamTags)
{
msg = j;
}
StreamTags() : JsonMessage(message_type::kStreamTags)
{
}
virtual ~StreamTags()
{
}
};
}
#endif

64
common/message/time.h Normal file
View file

@ -0,0 +1,64 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef TIME_MSG_H
#define TIME_MSG_H
#include "message.h"
namespace msg
{
class Time : public BaseMessage
{
public:
Time() : BaseMessage(message_type::kTime)
{
}
virtual ~Time()
{
}
virtual void read(std::istream& stream)
{
readVal(stream, latency.sec);
readVal(stream, latency.usec);
}
virtual uint32_t getSize() const
{
return sizeof(tv);
}
tv latency;
protected:
virtual void doserialize(std::ostream& stream) const
{
writeVal(stream, latency.sec);
writeVal(stream, latency.usec);
}
};
}
#endif

View file

@ -0,0 +1,93 @@
/***
This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef WIRE_CHUNK_H
#define WIRE_CHUNK_H
#include <chrono>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <streambuf>
#include <vector>
#include "message.h"
#include "common/timeDefs.h"
namespace msg
{
/**
* Piece of raw data
* Has information about "when" captured (timestamp)
*/
class WireChunk : public BaseMessage
{
public:
WireChunk(size_t size = 0) : BaseMessage(message_type::kWireChunk), payloadSize(size)
{
payload = (char*)malloc(size);
}
WireChunk(const WireChunk& wireChunk) : BaseMessage(message_type::kWireChunk), timestamp(wireChunk.timestamp), payloadSize(wireChunk.payloadSize)
{
payload = (char*)malloc(payloadSize);
memcpy(payload, wireChunk.payload, payloadSize);
}
virtual ~WireChunk()
{
free(payload);
}
virtual void read(std::istream& stream)
{
readVal(stream, timestamp.sec);
readVal(stream, timestamp.usec);
readVal(stream, &payload, payloadSize);
}
virtual uint32_t getSize() const
{
return sizeof(tv) + sizeof(int32_t) + payloadSize;
}
virtual chronos::time_point_clk start() const
{
return chronos::time_point_clk(chronos::sec(timestamp.sec) + chronos::usec(timestamp.usec));
}
tv timestamp;
uint32_t payloadSize;
char* payload;
protected:
virtual void doserialize(std::ostream& stream) const
{
writeVal(stream, timestamp.sec);
writeVal(stream, timestamp.usec);
writeVal(stream, payload, payloadSize);
}
};
}
#endif