add clang-format file

reformat code
This commit is contained in:
badaix 2019-09-24 22:42:36 +02:00
parent b733f646ea
commit b20add3815
105 changed files with 7773 additions and 7723 deletions

20
.clang-format Normal file
View file

@ -0,0 +1,20 @@
---
AccessModifierOffset: '-4'
AllowShortBlocksOnASingleLine: 'false'
AllowShortCaseLabelsOnASingleLine: 'false'
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: 'false'
AllowShortLoopsOnASingleLine: 'false'
AlwaysBreakTemplateDeclarations: 'true'
BreakBeforeBraces: Allman
ColumnLimit: '160'
IndentCaseLabels: 'true'
IndentWidth: '4'
Language: Cpp
MaxEmptyLinesToKeep: '3'
PenaltyBreakComment: '100000'
PointerAlignment: Left
Standard: Cpp11
UseTab: Never
...

View file

@ -1,5 +1,5 @@
# This file is part of snapcast # This file is part of snapcast
# Copyright (C) 2014-2018 Johannes Pohl # Copyright (C) 2014-2019 Johannes Pohl
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by

47
client/browseZeroConf/browseAvahi.cpp Executable file → Normal file
View file

@ -18,13 +18,13 @@
***/ ***/
#include "browseAvahi.h" #include "browseAvahi.h"
#include <stdio.h> #include "aixlog.hpp"
#include "common/snapException.h"
#include <assert.h> #include <assert.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <iostream>
#include "common/snapException.h"
#include "aixlog.hpp"
static AvahiSimplePoll* simple_poll = NULL; static AvahiSimplePoll* simple_poll = NULL;
@ -57,19 +57,9 @@ void BrowseAvahi::cleanUp()
} }
void BrowseAvahi::resolve_callback( void BrowseAvahi::resolve_callback(AvahiServiceResolver* r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol,
AvahiServiceResolver *r, AvahiResolverEvent event, const char* name, const char* type, const char* domain, const char* host_name,
AVAHI_GCC_UNUSED AvahiIfIndex interface, const AvahiAddress* address, uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags flags,
AVAHI_GCC_UNUSED AvahiProtocol protocol,
AvahiResolverEvent event,
const char *name,
const char *type,
const char *domain,
const char *host_name,
const AvahiAddress *address,
uint16_t port,
AvahiStringList *txt,
AvahiLookupResultFlags flags,
AVAHI_GCC_UNUSED void* userdata) AVAHI_GCC_UNUSED void* userdata)
{ {
BrowseAvahi* browseAvahi = static_cast<BrowseAvahi*>(userdata); BrowseAvahi* browseAvahi = static_cast<BrowseAvahi*>(userdata);
@ -80,7 +70,8 @@ void BrowseAvahi::resolve_callback(
switch (event) switch (event)
{ {
case AVAHI_RESOLVER_FAILURE: case AVAHI_RESOLVER_FAILURE:
LOG(ERROR) << "(Resolver) Failed to resolve service '" << name << "' of type '" << type << "' in domain '" << domain << "': " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))) << "\n"; LOG(ERROR) << "(Resolver) Failed to resolve service '" << name << "' of type '" << type << "' in domain '" << domain
<< "': " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))) << "\n";
break; break;
case AVAHI_RESOLVER_FOUND: case AVAHI_RESOLVER_FOUND:
@ -116,16 +107,8 @@ void BrowseAvahi::resolve_callback(
} }
void BrowseAvahi::browse_callback( void BrowseAvahi::browse_callback(AvahiServiceBrowser* b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char* name,
AvahiServiceBrowser *b, const char* type, const char* domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata)
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiBrowserEvent event,
const char *name,
const char *type,
const char *domain,
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
void* userdata)
{ {
// AvahiClient* client = (AvahiClient*)userdata; // AvahiClient* client = (AvahiClient*)userdata;
@ -149,7 +132,8 @@ void BrowseAvahi::browse_callback(
the callback function is called the server will free the callback function is called the server will free
the resolver for us. */ the resolver for us. */
if (!(avahi_service_resolver_new(browseAvahi->client_, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0, resolve_callback, userdata))) if (!(avahi_service_resolver_new(browseAvahi->client_, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0,
resolve_callback, userdata)))
LOG(ERROR) << "Failed to resolve service '" << name << "': " << avahi_strerror(avahi_client_errno(browseAvahi->client_)) << "\n"; LOG(ERROR) << "Failed to resolve service '" << name << "': " << avahi_strerror(avahi_client_errno(browseAvahi->client_)) << "\n";
break; break;
@ -195,7 +179,8 @@ bool BrowseAvahi::browse(const std::string& serviceName, mDNSResult& result, int
throw SnapException("BrowseAvahi - Failed to create client: " + std::string(avahi_strerror(error))); throw SnapException("BrowseAvahi - Failed to create client: " + std::string(avahi_strerror(error)));
/* Create the service browser */ /* Create the service browser */
if (!(sb_ = avahi_service_browser_new(client_, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, serviceName.c_str(), NULL, (AvahiLookupFlags)0, browse_callback, this))) if (!(sb_ =
avahi_service_browser_new(client_, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, serviceName.c_str(), NULL, (AvahiLookupFlags)0, browse_callback, this)))
throw SnapException("BrowseAvahi - Failed to create service browser: " + std::string(avahi_strerror(avahi_client_errno(client_)))); throw SnapException("BrowseAvahi - Failed to create service browser: " + std::string(avahi_strerror(avahi_client_errno(client_))));
result_.valid = false; result_.valid = false;
@ -220,5 +205,3 @@ bool BrowseAvahi::browse(const std::string& serviceName, mDNSResult& result, int
throw; throw;
} }
} }

14
client/browseZeroConf/browseAvahi.h Executable file → Normal file
View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -21,9 +21,9 @@
#include <avahi-client/client.h> #include <avahi-client/client.h>
#include <avahi-client/lookup.h> #include <avahi-client/lookup.h>
#include <avahi-common/simple-watch.h>
#include <avahi-common/malloc.h>
#include <avahi-common/error.h> #include <avahi-common/error.h>
#include <avahi-common/malloc.h>
#include <avahi-common/simple-watch.h>
class BrowseAvahi; class BrowseAvahi;
@ -38,8 +38,12 @@ public:
private: private:
void cleanUp(); void cleanUp();
static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, AVAHI_GCC_UNUSED void* userdata); static void resolve_callback(AvahiServiceResolver* r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol,
static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata); AvahiResolverEvent event, const char* name, const char* type, const char* domain, const char* host_name,
const AvahiAddress* address, uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags flags,
AVAHI_GCC_UNUSED void* userdata);
static void browse_callback(AvahiServiceBrowser* b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char* name,
const char* type, const char* domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata);
static void client_callback(AvahiClient* c, AvahiClientState state, AVAHI_GCC_UNUSED void* userdata); static void client_callback(AvahiClient* c, AvahiClientState state, AVAHI_GCC_UNUSED void* userdata);
AvahiClient* client_; AvahiClient* client_;
mDNSResult result_; mDNSResult result_;

61
client/browseZeroConf/browseBonjour.cpp Executable file → Normal file
View file

@ -1,14 +1,14 @@
#include "browseBonjour.h" #include "browseBonjour.h"
#include <memory>
#include <iostream>
#include <deque> #include <deque>
#include <iostream>
#include <memory>
#ifdef WINDOWS #ifdef WINDOWS
#include <WinSock2.h> #include <WinSock2.h>
#include <Ws2tcpip.h> #include <Ws2tcpip.h>
#else #else
#include <sys/socket.h>
#include <netdb.h> #include <netdb.h>
#include <sys/socket.h>
#endif #endif
#include "aixlog.hpp" #include "aixlog.hpp"
@ -141,7 +141,9 @@ struct mDNSResolve
uint16_t port; uint16_t port;
}; };
#define CHECKED(err) if((err)!=kDNSServiceErr_NoError)throw SnapException(BonjourGetError(err) + ":" + to_string(__LINE__)); #define CHECKED(err) \
if ((err) != kDNSServiceErr_NoError) \
throw SnapException(BonjourGetError(err) + ":" + to_string(__LINE__));
void runService(const DNSServiceHandle& service) void runService(const DNSServiceHandle& service)
{ {
@ -173,20 +175,14 @@ bool BrowseBonjour::browse(const string& serviceName, mDNSResult& result, int ti
{ {
DNSServiceHandle service(new DNSServiceRef(NULL)); DNSServiceHandle service(new DNSServiceRef(NULL));
CHECKED(DNSServiceBrowse(service.get(), 0, 0, serviceName.c_str(), "local.", CHECKED(DNSServiceBrowse(service.get(), 0, 0, serviceName.c_str(), "local.",
[](DNSServiceRef service, [](DNSServiceRef service, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
DNSServiceFlags flags, const char* serviceName, const char* regtype, const char* replyDomain, void* context) {
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char* serviceName,
const char* regtype,
const char* replyDomain,
void* context)
{
auto replyCollection = static_cast<deque<mDNSReply>*>(context); auto replyCollection = static_cast<deque<mDNSReply>*>(context);
CHECKED(errorCode); CHECKED(errorCode);
replyCollection->push_back(mDNSReply{string(serviceName), string(regtype), string(replyDomain)}); replyCollection->push_back(mDNSReply{string(serviceName), string(regtype), string(replyDomain)});
}, &replyCollection)); },
&replyCollection));
runService(service); runService(service);
} }
@ -196,23 +192,16 @@ bool BrowseBonjour::browse(const string& serviceName, mDNSResult& result, int ti
{ {
DNSServiceHandle service(new DNSServiceRef(NULL)); DNSServiceHandle service(new DNSServiceRef(NULL));
for (auto& reply : replyCollection) for (auto& reply : replyCollection)
CHECKED(DNSServiceResolve(service.get(), 0, 0, reply.name.c_str(), reply.regtype.c_str(), reply.domain.c_str(), CHECKED(
[](DNSServiceRef service, DNSServiceResolve(service.get(), 0, 0, reply.name.c_str(), reply.regtype.c_str(), reply.domain.c_str(),
DNSServiceFlags flags, [](DNSServiceRef service, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char* fullName,
uint32_t interfaceIndex, const char* hosttarget, uint16_t port, uint16_t txtLen, const unsigned char* txtRecord, void* context) {
DNSServiceErrorType errorCode,
const char* fullName,
const char* hosttarget,
uint16_t port,
uint16_t txtLen,
const unsigned char* txtRecord,
void* context)
{
auto resultCollection = static_cast<deque<mDNSResolve>*>(context); auto resultCollection = static_cast<deque<mDNSResolve>*>(context);
CHECKED(errorCode); CHECKED(errorCode);
resultCollection->push_back(mDNSResolve{string(hosttarget), ntohs(port)}); resultCollection->push_back(mDNSResolve{string(hosttarget), ntohs(port)});
}, &resolveCollection)); },
&resolveCollection));
runService(service); runService(service);
} }
@ -226,15 +215,8 @@ bool BrowseBonjour::browse(const string& serviceName, mDNSResult& result, int ti
{ {
resultCollection[i].port = resolve.port; resultCollection[i].port = resolve.port;
CHECKED(DNSServiceGetAddrInfo(service.get(), kDNSServiceFlagsLongLivedQuery, 0, kDNSServiceProtocol_IPv4, resolve.fullName.c_str(), CHECKED(DNSServiceGetAddrInfo(service.get(), kDNSServiceFlagsLongLivedQuery, 0, kDNSServiceProtocol_IPv4, resolve.fullName.c_str(),
[](DNSServiceRef service, [](DNSServiceRef service, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
DNSServiceFlags flags, const char* hostname, const sockaddr* address, uint32_t ttl, void* context) {
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char* hostname,
const sockaddr* address,
uint32_t ttl,
void* context)
{
auto result = static_cast<mDNSResult*>(context); auto result = static_cast<mDNSResult*>(context);
result->host = string(hostname); result->host = string(hostname);
@ -243,15 +225,14 @@ bool BrowseBonjour::browse(const string& serviceName, mDNSResult& result, int ti
char hostIP[NI_MAXHOST]; char hostIP[NI_MAXHOST];
char hostService[NI_MAXSERV]; char hostService[NI_MAXSERV];
if (getnameinfo(address, sizeof(*address), if (getnameinfo(address, sizeof(*address), hostIP, sizeof(hostIP), hostService, sizeof(hostService),
hostIP, sizeof(hostIP),
hostService, sizeof(hostService),
NI_NUMERICHOST | NI_NUMERICSERV) == 0) NI_NUMERICHOST | NI_NUMERICSERV) == 0)
result->ip = string(hostIP); result->ip = string(hostIP);
else else
return; return;
result->valid = true; result->valid = true;
}, &resultCollection[i++])); },
&resultCollection[i++]));
} }
runService(service); runService(service);
} }

0
client/browseZeroConf/browseBonjour.h Executable file → Normal file
View file

0
client/browseZeroConf/browsemDNS.h Executable file → Normal file
View file

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,19 +16,21 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include "clientConnection.h"
#include "aixlog.hpp"
#include "common/snapException.h"
#include "common/strCompat.h"
#include "message/hello.h"
#include <iostream> #include <iostream>
#include <mutex> #include <mutex>
#include "clientConnection.h"
#include "common/strCompat.h"
#include "common/snapException.h"
#include "message/hello.h"
#include "aixlog.hpp"
using namespace std; using namespace std;
ClientConnection::ClientConnection(MessageReceiver* receiver, const std::string& host, size_t port) : socket_(nullptr), active_(false), connected_(false), messageReceiver_(receiver), reqId_(1), host_(host), port_(port), readerThread_(NULL), sumTimeout_(chronos::msec(0)) ClientConnection::ClientConnection(MessageReceiver* receiver, const std::string& host, size_t port)
: socket_(nullptr), active_(false), connected_(false), messageReceiver_(receiver), reqId_(1), host_(host), port_(port), readerThread_(NULL),
sumTimeout_(chronos::msec(0))
{ {
} }
@ -49,8 +51,7 @@ void ClientConnection::socketRead(void* _to, size_t _bytes)
len += socket_->read_some(asio::buffer((char*)_to + len, toRead)); len += socket_->read_some(asio::buffer((char*)_to + len, toRead));
// cout << "len: " << len << ", error: " << error << endl; // cout << "len: " << len << ", error: " << error << endl;
toRead = _bytes - len; toRead = _bytes - len;
} } while (toRead > 0);
while (toRead > 0);
} }
@ -99,9 +100,11 @@ void ClientConnection::stop()
if (socket_) if (socket_)
{ {
socket_->shutdown(asio::ip::tcp::socket::shutdown_both, ec); socket_->shutdown(asio::ip::tcp::socket::shutdown_both, ec);
if (ec) LOG(ERROR) << "Error in socket shutdown: " << ec.message() << endl; if (ec)
LOG(ERROR) << "Error in socket shutdown: " << ec.message() << endl;
socket_->close(ec); socket_->close(ec);
if (ec) LOG(ERROR) << "Error in socket close: " << ec.message() << endl; if (ec)
LOG(ERROR) << "Error in socket close: " << ec.message() << endl;
} }
if (readerThread_) if (readerThread_)
{ {
@ -174,7 +177,8 @@ void ClientConnection::getNextMessage()
vector<char> buffer(baseMsgSize); vector<char> buffer(baseMsgSize);
socketRead(&buffer[0], baseMsgSize); socketRead(&buffer[0], baseMsgSize);
baseMessage.deserialize(&buffer[0]); baseMessage.deserialize(&buffer[0]);
// LOG(DEBUG) << "getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " << baseMessage.refersTo << "\n"; // LOG(DEBUG) << "getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " <<
//baseMessage.refersTo << "\n";
if (baseMessage.size > buffer.size()) if (baseMessage.size > buffer.size())
buffer.resize(baseMessage.size); buffer.resize(baseMessage.size);
// { // {
@ -186,7 +190,8 @@ void ClientConnection::getNextMessage()
{ {
std::unique_lock<std::mutex> lock(pendingRequestsMutex_); std::unique_lock<std::mutex> lock(pendingRequestsMutex_);
// LOG(DEBUG) << "got lock - getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " << baseMessage.refersTo << "\n"; // LOG(DEBUG) << "got lock - getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ",
//refers: " << baseMessage.refersTo << "\n";
{ {
for (auto req : pendingRequests_) for (auto req : pendingRequests_)
{ {
@ -230,7 +235,3 @@ void ClientConnection::reader()
connected_ = false; connected_ = false;
active_ = false; active_ = false;
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,16 +19,16 @@
#ifndef CLIENT_CONNECTION_H #ifndef CLIENT_CONNECTION_H
#define CLIENT_CONNECTION_H #define CLIENT_CONNECTION_H
#include "common/timeDefs.h"
#include "message/message.h"
#include <asio.hpp>
#include <atomic>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <set>
#include <string> #include <string>
#include <thread> #include <thread>
#include <atomic>
#include <mutex>
#include <memory>
#include <asio.hpp>
#include <condition_variable>
#include <set>
#include "message/message.h"
#include "common/timeDefs.h"
using asio::ip::tcp; using asio::ip::tcp;
@ -130,7 +130,3 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,37 +16,29 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <iostream>
#include <string>
#include <memory>
#include "controller.h" #include "controller.h"
#include "decoder/pcmDecoder.h" #include "decoder/pcmDecoder.h"
#include <iostream>
#include <memory>
#include <string>
#if defined(HAS_OGG) && (defined(HAS_TREMOR) || defined(HAS_VORBIS)) #if defined(HAS_OGG) && (defined(HAS_TREMOR) || defined(HAS_VORBIS))
#include "decoder/oggDecoder.h" #include "decoder/oggDecoder.h"
#endif #endif
#if defined(HAS_FLAC) #if defined(HAS_FLAC)
#include "decoder/flacDecoder.h" #include "decoder/flacDecoder.h"
#endif #endif
#include "timeProvider.h"
#include "message/time.h"
#include "message/hello.h"
#include "common/snapException.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/snapException.h"
#include "message/hello.h"
#include "message/time.h"
#include "timeProvider.h"
using namespace std; using namespace std;
Controller::Controller(const std::string& hostId, size_t instance, std::shared_ptr<MetadataAdapter> meta) : MessageReceiver(), Controller::Controller(const std::string& hostId, size_t instance, std::shared_ptr<MetadataAdapter> meta)
hostId_(hostId), : MessageReceiver(), hostId_(hostId), instance_(instance), active_(false), latency_(0), stream_(nullptr), decoder_(nullptr), player_(nullptr), meta_(meta),
instance_(instance), serverSettings_(nullptr), async_exception_(nullptr)
active_(false),
latency_(0),
stream_(nullptr),
decoder_(nullptr),
player_(nullptr),
meta_(meta),
serverSettings_(nullptr),
async_exception_(nullptr)
{ {
} }
@ -72,7 +64,8 @@ void Controller::onMessageReceived(ClientConnection* connection, const msg::Base
{ {
// TODO: do decoding in thread? // TODO: do decoding in thread?
stream_->addChunk(pcmChunk); stream_->addChunk(pcmChunk);
//LOG(DEBUG) << ", decoded: " << pcmChunk->payloadSize << ", Duration: " << pcmChunk->getDuration() << ", sec: " << pcmChunk->timestamp.sec << ", usec: " << pcmChunk->timestamp.usec/1000 << ", type: " << pcmChunk->type << "\n"; // LOG(DEBUG) << ", decoded: " << pcmChunk->payloadSize << ", Duration: " << pcmChunk->getDuration() << ", sec: " << pcmChunk->timestamp.sec <<
// ", usec: " << pcmChunk->timestamp.usec/1000 << ", type: " << pcmChunk->type << "\n";
} }
else else
delete pcmChunk; delete pcmChunk;
@ -88,7 +81,8 @@ void Controller::onMessageReceived(ClientConnection* connection, const msg::Base
{ {
serverSettings_.reset(new msg::ServerSettings()); serverSettings_.reset(new msg::ServerSettings());
serverSettings_->deserialize(baseMessage, buffer); serverSettings_->deserialize(baseMessage, buffer);
LOG(INFO) << "ServerSettings - buffer: " << serverSettings_->getBufferMs() << ", latency: " << serverSettings_->getLatency() << ", volume: " << serverSettings_->getVolume() << ", muted: " << serverSettings_->isMuted() << "\n"; LOG(INFO) << "ServerSettings - buffer: " << serverSettings_->getBufferMs() << ", latency: " << serverSettings_->getLatency()
<< ", volume: " << serverSettings_->getVolume() << ", muted: " << serverSettings_->isMuted() << "\n";
if (stream_ && player_) if (stream_ && player_)
{ {
player_->setVolume(serverSettings_->getVolume() / 100.); player_->setVolume(serverSettings_->getVolume() / 100.);
@ -254,6 +248,3 @@ void Controller::worker()
} }
LOG(DEBUG) << "Thread stopped\n"; LOG(DEBUG) << "Thread stopped\n";
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,13 +19,13 @@
#ifndef CONTROLLER_H #ifndef CONTROLLER_H
#define CONTROLLER_H #define CONTROLLER_H
#include <thread>
#include <atomic>
#include "decoder/decoder.h" #include "decoder/decoder.h"
#include "message/message.h" #include "message/message.h"
#include "message/serverSettings.h" #include "message/serverSettings.h"
#include "message/streamTags.h" #include "message/streamTags.h"
#include "player/pcmDevice.h" #include "player/pcmDevice.h"
#include <atomic>
#include <thread>
#ifdef HAS_ALSA #ifdef HAS_ALSA
#include "player/alsaPlayer.h" #include "player/alsaPlayer.h"
#elif HAS_OPENSL #elif HAS_OPENSL
@ -34,8 +34,8 @@
#include "player/coreAudioPlayer.h" #include "player/coreAudioPlayer.h"
#endif #endif
#include "clientConnection.h" #include "clientConnection.h"
#include "stream.h"
#include "metadata.h" #include "metadata.h"
#include "stream.h"
/// Forwards PCM data to the audio player /// Forwards PCM data to the audio player
@ -86,4 +86,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,10 +18,10 @@
#ifndef DECODER_H #ifndef DECODER_H
#define DECODER_H #define DECODER_H
#include <mutex>
#include "message/pcmChunk.h"
#include "message/codecHeader.h"
#include "common/sampleFormat.h" #include "common/sampleFormat.h"
#include "message/codecHeader.h"
#include "message/pcmChunk.h"
#include <mutex>
class Decoder class Decoder
@ -38,5 +38,3 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,20 +16,21 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <iostream>
#include <cstring>
#include <cmath>
#include "flacDecoder.h" #include "flacDecoder.h"
#include "common/snapException.h"
#include "common/endian.hpp"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/endian.hpp"
#include "common/snapException.h"
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std; using namespace std;
static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data); static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data);
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame, const FLAC__int32* const buffer[],
void* client_data);
static void metadata_callback(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata* metadata, void* client_data); static void metadata_callback(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata* metadata, void* client_data);
static void error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data); static void error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data);
@ -144,7 +145,8 @@ FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder,
} }
FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame, const FLAC__int32* const buffer[],
void* client_data)
{ {
(void)decoder; (void)decoder;
@ -199,10 +201,7 @@ void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMet
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
{ {
static_cast<FlacDecoder*>(client_data)->cacheInfo_.sampleRate_ = metadata->data.stream_info.sample_rate; static_cast<FlacDecoder*>(client_data)->cacheInfo_.sampleRate_ = metadata->data.stream_info.sample_rate;
sampleFormat.setFormat( sampleFormat.setFormat(metadata->data.stream_info.sample_rate, metadata->data.stream_info.bits_per_sample, metadata->data.stream_info.channels);
metadata->data.stream_info.sample_rate,
metadata->data.stream_info.bits_per_sample,
metadata->data.stream_info.channels);
} }
} }
@ -223,8 +222,3 @@ void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderError
// Oct 27 17:47:13 kitchen snapclient[869]: Got error callback: FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM // Oct 27 17:47:13 kitchen snapclient[869]: Got error callback: FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
// Oct 27 17:47:13 kitchen snapclient[869]: Got error callback: FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC // Oct 27 17:47:13 kitchen snapclient[869]: Got error callback: FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -60,5 +60,3 @@ public:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <iostream>
#include <cstring>
#include <cmath> #include <cmath>
#include <cstring>
#include <iostream>
#include "oggDecoder.h"
#include "common/snapException.h"
#include "common/endian.hpp"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/endian.hpp"
#include "common/snapException.h"
#include "oggDecoder.h"
using namespace std; using namespace std;
@ -229,7 +229,8 @@ SampleFormat OggDecoder::setHeader(msg::CodecHeader* chunk)
std::string comment(*ptr); std::string comment(*ptr);
if (comment.find("SAMPLE_FORMAT=") == 0) if (comment.find("SAMPLE_FORMAT=") == 0)
sampleFormat_.setFormat(comment.substr(comment.find("=") + 1)); sampleFormat_.setFormat(comment.substr(comment.find("=") + 1));
LOG(INFO) << "comment: " << comment << "\n";; LOG(INFO) << "comment: " << comment << "\n";
;
++ptr; ++ptr;
} }
@ -237,6 +238,3 @@ SampleFormat OggDecoder::setHeader(msg::CodecHeader* chunk)
return sampleFormat_; return sampleFormat_;
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -39,8 +39,10 @@ private:
template <typename T> template <typename T>
T clip(const T& value, const T& lower, const T& upper) const T clip(const T& value, const T& lower, const T& upper) const
{ {
if (value > upper) return upper; if (value > upper)
if (value < lower) return lower; return upper;
if (value < lower)
return lower;
return value; return value;
} }
@ -59,5 +61,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,10 +16,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include "common/snapException.h"
#include "common/endian.hpp"
#include "aixlog.hpp"
#include "pcmDecoder.h" #include "pcmDecoder.h"
#include "aixlog.hpp"
#include "common/endian.hpp"
#include "common/snapException.h"
#define ID_RIFF 0x46464952 #define ID_RIFF 0x46464952
@ -108,21 +108,13 @@ SampleFormat PcmDecoder::setHeader(msg::CodecHeader* chunk)
/// Unknown chunk, skip bytes /// Unknown chunk, skip bytes
pos += SWAP_32(chunk_header.sz); pos += SWAP_32(chunk_header.sz);
} }
} } while (moreChunks);
while (moreChunks);
if (SWAP_32(chunk_fmt.sample_rate) == 0) if (SWAP_32(chunk_fmt.sample_rate) == 0)
throw SnapException("Sample format not found"); throw SnapException("Sample format not found");
SampleFormat sampleFormat( SampleFormat sampleFormat(SWAP_32(chunk_fmt.sample_rate), SWAP_16(chunk_fmt.bits_per_sample), SWAP_16(chunk_fmt.num_channels));
SWAP_32(chunk_fmt.sample_rate),
SWAP_16(chunk_fmt.bits_per_sample),
SWAP_16(chunk_fmt.num_channels));
return sampleFormat; return sampleFormat;
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -31,5 +31,3 @@ public:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,8 +19,8 @@
#ifndef DOUBLE_BUFFER_H #ifndef DOUBLE_BUFFER_H
#define DOUBLE_BUFFER_H #define DOUBLE_BUFFER_H
#include<deque>
#include <algorithm> #include <algorithm>
#include <deque>
/// Size limited queue /// Size limited queue
@ -126,11 +126,8 @@ public:
private: private:
size_t bufferSize; size_t bufferSize;
std::deque<T> buffer; std::deque<T> buffer;
}; };
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -98,7 +98,6 @@ public:
std::cerr << serialize() << "\n"; std::cerr << serialize() << "\n";
return 0; return 0;
} }
}; };
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -26,8 +26,7 @@
using namespace std; using namespace std;
AlsaPlayer::AlsaPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream) : AlsaPlayer::AlsaPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream) : Player(pcmDevice, stream), handle_(NULL), buff_(NULL)
Player(pcmDevice, stream), handle_(NULL), buff_(NULL)
{ {
} }
@ -273,9 +272,12 @@ vector<PcmDevice> AlsaPlayer::pcm_list(void)
if (io != NULL && strcmp(io, "Output") != 0) if (io != NULL && strcmp(io, "Output") != 0)
goto __end; goto __end;
pcmDevice.name = name; pcmDevice.name = name;
if(descr == NULL) { if (descr == NULL)
{
pcmDevice.description = ""; pcmDevice.description = "";
} else { }
else
{
pcmDevice.description = descr; pcmDevice.description = descr;
} }
pcmDevice.idx = idx++; pcmDevice.idx = idx++;
@ -293,4 +295,3 @@ __end:
snd_device_name_free_hint(hints); snd_device_name_free_hint(hints);
return result; return result;
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -54,4 +54,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,8 +17,8 @@
***/ ***/
//#include <CoreServices/CoreServices.h> //#include <CoreServices/CoreServices.h>
#include <CoreAudio/CoreAudio.h>
#include "coreAudioPlayer.h" #include "coreAudioPlayer.h"
#include <CoreAudio/CoreAudio.h>
#define NUM_BUFFERS 2 #define NUM_BUFFERS 2
@ -33,10 +33,7 @@ void callback(void *custom_data, AudioQueueRef queue, AudioQueueBufferRef buffer
} }
CoreAudioPlayer::CoreAudioPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream) : CoreAudioPlayer::CoreAudioPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream) : Player(pcmDevice, stream), ms_(100), pubStream_(stream)
Player(pcmDevice, stream),
ms_(100),
pubStream_(stream)
{ {
} }
@ -51,9 +48,7 @@ std::vector<PcmDevice> CoreAudioPlayer::pcm_list(void)
{ {
UInt32 propsize; UInt32 propsize;
AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyDevices, AudioObjectPropertyAddress theAddress = {kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &theAddress, 0, NULL, &propsize); AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &theAddress, 0, NULL, &propsize);
int nDevices = propsize / sizeof(AudioDeviceID); int nDevices = propsize / sizeof(AudioDeviceID);

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -58,4 +58,3 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,10 +19,10 @@
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
#include "openslPlayer.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/snapException.h" #include "common/snapException.h"
#include "common/strCompat.h" #include "common/strCompat.h"
#include "openslPlayer.h"
using namespace std; using namespace std;
@ -43,19 +43,9 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
OpenslPlayer::OpenslPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream) : OpenslPlayer::OpenslPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream)
Player(pcmDevice, stream), : Player(pcmDevice, stream), engineObject(NULL), engineEngine(NULL), outputMixObject(NULL), bqPlayerObject(NULL), bqPlayerPlay(NULL),
engineObject(NULL), bqPlayerBufferQueue(NULL), bqPlayerVolume(NULL), curBuffer(0), ms_(50), buff_size(0), pubStream_(stream)
engineEngine(NULL),
outputMixObject(NULL),
bqPlayerObject(NULL),
bqPlayerPlay(NULL),
bqPlayerBufferQueue(NULL),
bqPlayerVolume(NULL),
curBuffer(0),
ms_(50),
buff_size(0),
pubStream_(stream)
{ {
initOpensl(); initOpensl();
} }
@ -200,10 +190,7 @@ void OpenslPlayer::initOpensl()
SLresult result; SLresult result;
// create engine // create engine
SLEngineOption engineOption[] = SLEngineOption engineOption[] = {{(SLuint32)SL_ENGINEOPTION_THREADSAFE, (SLuint32)SL_BOOLEAN_TRUE}};
{
{(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
};
result = slCreateEngine(&engineObject, 1, engineOption, 0, NULL, NULL); result = slCreateEngine(&engineObject, 1, engineOption, 0, NULL, NULL);
throwUnsuccess("slCreateEngine", result); throwUnsuccess("slCreateEngine", result);
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
@ -284,16 +271,9 @@ void OpenslPlayer::initOpensl()
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM format_pcm = SLDataFormat_PCM format_pcm = {
{ SL_DATAFORMAT_PCM, format.channels, samplesPerSec, bitsPerSample, containerSize, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_DATAFORMAT_PCM, SL_BYTEORDER_LITTLEENDIAN};
format.channels,
samplesPerSec,
bitsPerSample,
containerSize,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN
};
SLDataSource audioSrc = {&loc_bufq, &format_pcm}; SLDataSource audioSrc = {&loc_bufq, &format_pcm};
@ -413,4 +393,3 @@ void OpenslPlayer::stop()
void OpenslPlayer::worker() void OpenslPlayer::worker()
{ {
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -74,4 +74,3 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -24,15 +24,9 @@
struct PcmDevice struct PcmDevice
{ {
PcmDevice() : PcmDevice() : idx(-1), name("default"){};
idx(-1), name("default")
{
};
PcmDevice(int idx, const std::string& name, const std::string& description = "") : PcmDevice(int idx, const std::string& name, const std::string& description = "") : idx(idx), name(name), description(description){};
idx(idx), name(name), description(description)
{
};
int idx; int idx;
std::string name; std::string name;
@ -41,4 +35,3 @@ struct PcmDevice
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,23 +16,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <iostream>
#include <cmath> #include <cmath>
#include <iostream>
#include "player.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "player.h"
using namespace std; using namespace std;
Player::Player(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream) : Player::Player(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream)
active_(false), : active_(false), stream_(stream), pcmDevice_(pcmDevice), volume_(1.0), muted_(false), volCorrection_(1.0)
stream_(stream),
pcmDevice_(pcmDevice),
volume_(1.0),
muted_(false),
volCorrection_(1.0)
{ {
} }
@ -113,5 +108,3 @@ void Player::setMute(bool mute)
{ {
muted_ = mute; muted_ = mute;
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,14 +19,14 @@
#ifndef PLAYER_H #ifndef PLAYER_H
#define PLAYER_H #define PLAYER_H
#include "aixlog.hpp"
#include "common/endian.hpp"
#include "pcmDevice.h"
#include "stream.h"
#include <atomic>
#include <string> #include <string>
#include <thread> #include <thread>
#include <atomic>
#include <vector> #include <vector>
#include "stream.h"
#include "pcmDevice.h"
#include "common/endian.hpp"
#include "aixlog.hpp"
/// Audio Player /// Audio Player
@ -72,4 +72,3 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,9 +19,9 @@
#include <iostream> #include <iostream>
#include <sys/resource.h> #include <sys/resource.h>
#include "popl.hpp"
#include "controller.h"
#include "browseZeroConf/browsemDNS.h" #include "browseZeroConf/browsemDNS.h"
#include "controller.h"
#include "popl.hpp"
#ifdef HAS_ALSA #ifdef HAS_ALSA
#include "player/alsaPlayer.h" #include "player/alsaPlayer.h"
@ -131,8 +131,7 @@ int main (int argc, char **argv)
vector<PcmDevice> pcmDevices = AlsaPlayer::pcm_list(); vector<PcmDevice> pcmDevices = AlsaPlayer::pcm_list();
for (auto dev : pcmDevices) for (auto dev : pcmDevices)
{ {
cout << dev.idx << ": " << dev.name << "\n" cout << dev.idx << ": " << dev.name << "\n" << dev.description << "\n\n";
<< dev.description << "\n\n";
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@ -162,7 +161,8 @@ int main (int argc, char **argv)
{ {
AixLog::Log::instance().add_logsink<AixLog::SinkCout>(AixLog::Severity::trace, AixLog::Type::all, "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)"); AixLog::Log::instance().add_logsink<AixLog::SinkCout>(AixLog::Severity::trace, AixLog::Type::all, "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)");
if (!debugOption->value().empty()) if (!debugOption->value().empty())
AixLog::Log::instance().add_logsink<AixLog::SinkFile>(AixLog::Severity::trace, AixLog::Type::all, debugOption->value(), "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)"); AixLog::Log::instance().add_logsink<AixLog::SinkFile>(AixLog::Severity::trace, AixLog::Type::all, debugOption->value(),
"%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)");
} }
else else
{ {
@ -268,5 +268,3 @@ int main (int argc, char **argv)
SLOG(NOTICE) << "daemon terminated." << endl; SLOG(NOTICE) << "daemon terminated." << endl;
exit(exitcode); exit(exitcode);
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,18 +17,19 @@
***/ ***/
#include "stream.h" #include "stream.h"
#include "aixlog.hpp"
#include "timeProvider.h"
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include <string.h> #include <string.h>
#include "aixlog.hpp"
#include "timeProvider.h"
using namespace std; using namespace std;
// using namespace chronos; // using namespace chronos;
namespace cs = chronos; namespace cs = chronos;
Stream::Stream(const SampleFormat& sampleFormat) : format_(sampleFormat), sleep_(0), median_(0), shortMedian_(0), lastUpdate_(0), playedFrames_(0), bufferMs_(cs::msec(500)) Stream::Stream(const SampleFormat& sampleFormat)
: format_(sampleFormat), sleep_(0), median_(0), shortMedian_(0), lastUpdate_(0), playedFrames_(0), bufferMs_(cs::msec(500))
{ {
buffer_.setSize(500); buffer_.setSize(500);
shortBuffer_.setSize(100); shortBuffer_.setSize(100);
@ -242,7 +243,8 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
{ {
LOG(INFO) << "sleep < -bufferDuration/2: " << cs::duration<cs::msec>(sleep_) << " < " << -cs::duration<cs::msec>(bufferDuration) / 2 << ", "; LOG(INFO) << "sleep < -bufferDuration/2: " << cs::duration<cs::msec>(sleep_) << " < " << -cs::duration<cs::msec>(bufferDuration) / 2 << ", ";
// We're early: not enough chunks_. play silence. Reference chunk_ is the oldest (front) one // We're early: not enough chunks_. play silence. Reference chunk_ is the oldest (front) one
sleep_ = chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - getSilentPlayerChunk(outputBuffer, framesPerBuffer) - bufferMs_ + outputBufferDacTime); sleep_ = chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - getSilentPlayerChunk(outputBuffer, framesPerBuffer) - bufferMs_ +
outputBufferDacTime);
LOG(INFO) << "sleep: " << cs::duration<cs::msec>(sleep_) << "\n"; LOG(INFO) << "sleep: " << cs::duration<cs::msec>(sleep_) << "\n";
if (sleep_ < -bufferDuration / 2) if (sleep_ < -bufferDuration / 2)
return true; return true;
@ -253,7 +255,9 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
// We're late: discard oldest chunks // We're late: discard oldest chunks
while (sleep_ > chunk_->duration<cs::usec>()) while (sleep_ > chunk_->duration<cs::usec>())
{ {
LOG(INFO) << "sleep > chunkDuration: " << cs::duration<cs::msec>(sleep_) << " > " << chunk_->duration<cs::msec>().count() << ", chunks: " << chunks_.size() << ", out: " << cs::duration<cs::msec>(outputBufferDacTime) << ", needed: " << cs::duration<cs::msec>(bufferDuration) << "\n"; LOG(INFO) << "sleep > chunkDuration: " << cs::duration<cs::msec>(sleep_) << " > " << chunk_->duration<cs::msec>().count()
<< ", chunks: " << chunks_.size() << ", out: " << cs::duration<cs::msec>(outputBufferDacTime)
<< ", needed: " << cs::duration<cs::msec>(bufferDuration) << "\n";
sleep_ = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - chunk_->start() - bufferMs_ + outputBufferDacTime); sleep_ = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - chunk_->start() - bufferMs_ + outputBufferDacTime);
if (!chunks_.try_pop(chunk_, outputBufferDacTime)) if (!chunks_.try_pop(chunk_, outputBufferDacTime))
{ {
@ -294,7 +298,9 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
playedFrames_ -= abs(correctAfterXFrames_); playedFrames_ -= abs(correctAfterXFrames_);
} }
age = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, outputBufferDacTime, framesPerBuffer, framesCorrection) - bufferMs_ + outputBufferDacTime); age = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() -
getNextPlayerChunk(outputBuffer, outputBufferDacTime, framesPerBuffer, framesCorrection) - bufferMs_ +
outputBufferDacTime);
setRealSampleRate(format_.rate); setRealSampleRate(format_.rate);
if (sleep_.count() == 0) if (sleep_.count() == 0)
@ -341,7 +347,8 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
if (lastAge != msAge) if (lastAge != msAge)
{ {
lastAge = msAge; lastAge = msAge;
LOG(INFO) << "Sleep " << cs::duration<cs::msec>(sleep_) << ", age: " << msAge << ", bufferDuration: " << cs::duration<cs::msec>(bufferDuration) << "\n"; LOG(INFO) << "Sleep " << cs::duration<cs::msec>(sleep_) << ", age: " << msAge << ", bufferDuration: " << cs::duration<cs::msec>(bufferDuration)
<< "\n";
} }
} }
else if (shortBuffer_.full()) else if (shortBuffer_.full())
@ -361,8 +368,10 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
lastUpdate_ = now; lastUpdate_ = now;
median_ = buffer_.median(); median_ = buffer_.median();
shortMedian_ = shortBuffer_.median(); shortMedian_ = shortBuffer_.median();
LOG(INFO) << "Chunk: " << age.count()/100 << "\t" << miniBuffer_.median()/100 << "\t" << shortMedian_/100 << "\t" << median_/100 << "\t" << buffer_.size() << "\t" << cs::duration<cs::msec>(outputBufferDacTime) << "\n"; LOG(INFO) << "Chunk: " << age.count() / 100 << "\t" << miniBuffer_.median() / 100 << "\t" << shortMedian_ / 100 << "\t" << median_ / 100 << "\t"
// LOG(INFO) << "Chunk: " << age.count()/1000 << "\t" << miniBuffer_.median()/1000 << "\t" << shortMedian_/1000 << "\t" << median_/1000 << "\t" << buffer_.size() << "\t" << cs::duration<cs::msec>(outputBufferDacTime) << "\n"; << buffer_.size() << "\t" << cs::duration<cs::msec>(outputBufferDacTime) << "\n";
// LOG(INFO) << "Chunk: " << age.count()/1000 << "\t" << miniBuffer_.median()/1000 << "\t" << shortMedian_/1000 << "\t" << median_/1000 << "\t"
//<< buffer_.size() << "\t" << cs::duration<cs::msec>(outputBufferDacTime) << "\n";
} }
return (abs(cs::duration<cs::msec>(age)) < 500); return (abs(cs::duration<cs::msec>(age)) < 500);
} }
@ -372,6 +381,3 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
return false; return false;
} }
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -25,13 +25,13 @@
//#include <chrono> //#include <chrono>
//#include "common/timeUtils.h" //#include "common/timeUtils.h"
#include <deque> #include "common/queue.h"
#include <memory> #include "common/sampleFormat.h"
#include "doubleBuffer.h" #include "doubleBuffer.h"
#include "message/message.h" #include "message/message.h"
#include "message/pcmChunk.h" #include "message/pcmChunk.h"
#include "common/sampleFormat.h" #include <deque>
#include "common/queue.h" #include <memory>
/// Time synchronized audio stream /// Time synchronized audio stream
@ -94,5 +94,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -61,4 +61,3 @@ long TimeProvider::getPercentileDiffToServer(size_t percentile)
return diffBuffer.percentile(percentile); return diffBuffer.percentile(percentile);
} }
*/ */

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,11 +19,11 @@
#ifndef TIME_PROVIDER_H #ifndef TIME_PROVIDER_H
#define TIME_PROVIDER_H #define TIME_PROVIDER_H
#include <atomic> #include "common/timeDefs.h"
#include <chrono>
#include "doubleBuffer.h" #include "doubleBuffer.h"
#include "message/message.h" #include "message/message.h"
#include "common/timeDefs.h" #include <atomic>
#include <chrono>
/// Provides local and server time /// Provides local and server time
@ -87,5 +87,3 @@ private:
#endif #endif

View file

@ -1,5 +1,5 @@
# This file is part of snapcast # This file is part of snapcast
# Copyright (C) 2014-2018 Johannes Pohl # Copyright (C) 2014-2019 Johannes Pohl
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,27 +18,24 @@
#include "daemon.h" #include "daemon.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <iostream>
#include "common/snapException.h" #include "common/snapException.h"
#include "common/strCompat.h" #include "common/strCompat.h"
#include "common/utils/file_utils.h"
#include "common/utils.h" #include "common/utils.h"
#include "common/utils/file_utils.h"
#include <fcntl.h>
#include <grp.h>
#include <iostream>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
Daemon::Daemon(const std::string& user, const std::string& group, const std::string& pidfile) : Daemon::Daemon(const std::string& user, const std::string& group, const std::string& pidfile)
pidFilehandle_(-1), : pidFilehandle_(-1), user_(user), group_(group), pidfile_(pidfile)
user_(user),
group_(group),
pidfile_(pidfile)
{ {
if (pidfile.empty() || pidfile.find('/') == std::string::npos) if (pidfile.empty() || pidfile.find('/') == std::string::npos)
throw SnapException("invalid pid file \"" + pidfile + "\""); throw SnapException("invalid pid file \"" + pidfile + "\"");
@ -166,6 +163,3 @@ void Daemon::daemonize()
close(STDOUT_FILENO); close(STDOUT_FILENO);
close(STDERR_FILENO); close(STDERR_FILENO);
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -62,10 +62,7 @@ protected:
writeVal(stream, payload, payloadSize); writeVal(stream, payload, payloadSize);
} }
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,9 +19,9 @@
#ifndef HELLO_MSG_H #ifndef HELLO_MSG_H
#define HELLO_MSG_H #define HELLO_MSG_H
#include "jsonMessage.h"
#include "common/utils.h"
#include "common/strCompat.h" #include "common/strCompat.h"
#include "common/utils.h"
#include "jsonMessage.h"
#include <string> #include <string>
@ -108,10 +108,7 @@ public:
return id; return id;
} }
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,8 +19,8 @@
#ifndef JSON_MESSAGE_H #ifndef JSON_MESSAGE_H
#define JSON_MESSAGE_H #define JSON_MESSAGE_H
#include "message.h"
#include "common/json.hpp" #include "common/json.hpp"
#include "message.h"
using json = nlohmann::json; using json = nlohmann::json;
@ -76,10 +76,7 @@ protected:
} }
} }
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,14 +19,14 @@
#ifndef MESSAGE_H #ifndef MESSAGE_H
#define MESSAGE_H #define MESSAGE_H
#include "common/endian.hpp"
#include "common/timeDefs.h"
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <streambuf> #include <streambuf>
#include <vector>
#include <sys/time.h> #include <sys/time.h>
#include "common/endian.hpp" #include <vector>
#include "common/timeDefs.h"
/* /*
template<typename CharT, typename TraitsT = std::char_traits<CharT> > template<typename CharT, typename TraitsT = std::char_traits<CharT> >
@ -290,9 +290,7 @@ protected:
} }
virtual void doserialize(std::ostream& stream) const virtual void doserialize(std::ostream& stream) const {};
{
};
}; };
@ -306,9 +304,6 @@ struct SerializedMessage
BaseMessage message; BaseMessage message;
char* buffer; char* buffer;
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,10 +19,10 @@
#ifndef PCM_CHUNK_H #ifndef PCM_CHUNK_H
#define PCM_CHUNK_H #define PCM_CHUNK_H
#include <chrono> #include "common/sampleFormat.h"
#include "message.h" #include "message.h"
#include "wireChunk.h" #include "wireChunk.h"
#include "common/sampleFormat.h" #include <chrono>
namespace msg namespace msg
@ -36,17 +36,11 @@ namespace msg
class PcmChunk : public WireChunk class PcmChunk : public WireChunk
{ {
public: public:
PcmChunk(const SampleFormat& sampleFormat, size_t ms) : PcmChunk(const SampleFormat& sampleFormat, size_t ms) : WireChunk(sampleFormat.rate * sampleFormat.frameSize * ms / 1000), format(sampleFormat), idx_(0)
WireChunk(sampleFormat.rate*sampleFormat.frameSize*ms / 1000),
format(sampleFormat),
idx_(0)
{ {
} }
PcmChunk(const PcmChunk& pcmChunk) : PcmChunk(const PcmChunk& pcmChunk) : WireChunk(pcmChunk), format(pcmChunk.format), idx_(0)
WireChunk(pcmChunk),
format(pcmChunk.format),
idx_(0)
{ {
} }
@ -70,7 +64,8 @@ public:
memcpy((char*)outputBuffer, (char*)(payload) + format.frameSize * idx_, format.frameSize * result); memcpy((char*)outputBuffer, (char*)(payload) + format.frameSize * idx_, format.frameSize * result);
idx_ += result; idx_ += result;
//logd << ", new idx: " << idx << ", result: " << result << ", wireChunk->length: " << wireChunk->length << ", format.frameSize: " << format.frameSize << "\n";//std::endl; // logd << ", new idx: " << idx << ", result: " << result << ", wireChunk->length: " << wireChunk->length << ", format.frameSize: " << format.frameSize
// << "\n";//std::endl;
return result; return result;
} }
@ -89,11 +84,8 @@ public:
virtual chronos::time_point_clk start() const virtual chronos::time_point_clk start() const
{ {
return chronos::time_point_clk( return chronos::time_point_clk(chronos::sec(timestamp.sec) + chronos::usec(timestamp.usec) +
chronos::sec(timestamp.sec) + chronos::usec((chronos::usec::rep)(1000000. * ((double)idx_ / (double)format.rate))));
chronos::usec(timestamp.usec) +
chronos::usec((chronos::usec::rep)(1000000. * ((double)idx_ / (double)format.rate)))
);
} }
inline chronos::time_point_clk end() const inline chronos::time_point_clk end() const
@ -133,9 +125,6 @@ public:
private: private:
uint32_t idx_; uint32_t idx_;
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -82,10 +82,7 @@ public:
msg["muted"] = muted; msg["muted"] = muted;
} }
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -69,10 +69,7 @@ public:
{ {
} }
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -55,10 +55,7 @@ protected:
writeVal(stream, latency.usec); writeVal(stream, latency.usec);
} }
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,14 +19,14 @@
#ifndef WIRE_CHUNK_H #ifndef WIRE_CHUNK_H
#define WIRE_CHUNK_H #define WIRE_CHUNK_H
#include "common/timeDefs.h"
#include "message.h"
#include <chrono> #include <chrono>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <streambuf> #include <streambuf>
#include <vector> #include <vector>
#include "message.h"
#include "common/timeDefs.h"
namespace msg namespace msg
@ -84,10 +84,7 @@ protected:
writeVal(stream, payload, payloadSize); writeVal(stream, payload, payloadSize);
} }
}; };
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,17 +19,16 @@
#ifndef QUEUE_H #ifndef QUEUE_H
#define QUEUE_H #define QUEUE_H
#include <deque>
#include <atomic> #include <atomic>
#include <thread>
#include <mutex>
#include <condition_variable> #include <condition_variable>
#include <deque>
#include <mutex>
#include <thread>
template <typename T> template <typename T>
class Queue class Queue
{ {
public: public:
T pop() T pop()
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
@ -161,5 +160,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,15 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <vector>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <vector>
#include "sampleFormat.h"
#include "common/strCompat.h"
#include "common/utils/string_utils.h"
#include "common/utils.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/strCompat.h"
#include "common/utils.h"
#include "common/utils/string_utils.h"
#include "sampleFormat.h"
using namespace std; using namespace std;
@ -60,10 +60,7 @@ void SampleFormat::setFormat(const std::string& format)
std::vector<std::string> strs; std::vector<std::string> strs;
strs = utils::string::split(format, ':'); strs = utils::string::split(format, ':');
if (strs.size() == 3) if (strs.size() == 3)
setFormat( setFormat(cpt::stoul(strs[0]), cpt::stoul(strs[1]), cpt::stoul(strs[2]));
cpt::stoul(strs[0]),
cpt::stoul(strs[1]),
cpt::stoul(strs[2]));
} }
@ -81,5 +78,3 @@ void SampleFormat::setFormat(uint32_t rate, uint16_t bits, uint16_t channels)
frameSize = channels * sampleSize; frameSize = channels * sampleSize;
// LOG(DEBUG) << "SampleFormat: " << rate << ":" << bits << ":" << channels << "\n"; // LOG(DEBUG) << "SampleFormat: " << rate << ":" << bits << ":" << channels << "\n";
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -31,7 +31,8 @@
* 1 frame represents 1 analog sample from all channels; here we have 2 channels, and so: * 1 frame represents 1 analog sample from all channels; here we have 2 channels, and so:
* 1 frame = (num_channels) * (1 sample in bytes) = (2 channels) * (2 bytes (16 bits) per sample) = 4 bytes (32 bits) * 1 frame = (num_channels) * (1 sample in bytes) = (2 channels) * (2 bytes (16 bits) per sample) = 4 bytes (32 bits)
* To sustain 2x 44.1 KHz analog rate - the system must be capable of data transfer rate, in Bytes/sec: * To sustain 2x 44.1 KHz analog rate - the system must be capable of data transfer rate, in Bytes/sec:
* Bps_rate = (num_channels) * (1 sample in bytes) * (analog_rate) = (1 frame) * (analog_rate) = ( 2 channels ) * (2 bytes/sample) * (44100 samples/sec) = 2*2*44100 = 176400 Bytes/sec (link to formula img) * Bps_rate = (num_channels) * (1 sample in bytes) * (analog_rate) = (1 frame) * (analog_rate) = ( 2 channels ) * (2 bytes/sample) * (44100 samples/sec) =
* 2*2*44100 = 176400 Bytes/sec (link to formula img)
*/ */
class SampleFormat class SampleFormat
{ {
@ -73,4 +74,3 @@ public:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -47,5 +47,3 @@ void signal_handler(int sig)
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,13 +19,15 @@
#ifndef SNAP_EXCEPTION_H #ifndef SNAP_EXCEPTION_H
#define SNAP_EXCEPTION_H #define SNAP_EXCEPTION_H
#include <cstring> // std::strlen, std::strcpy
#include <exception> #include <exception>
#include <string> #include <string>
#include <cstring> // std::strlen, std::strcpy
// text_exception uses a dynamically-allocated internal c-string for what(): // text_exception uses a dynamically-allocated internal c-string for what():
class SnapException : public std::exception { class SnapException : public std::exception
{
char* text_; char* text_;
public: public:
SnapException(const char* text) SnapException(const char* text)
{ {
@ -78,5 +80,3 @@ public:
#endif #endif

View file

@ -2,16 +2,16 @@
#define COMPAT_H #define COMPAT_H
#include <string>
#include <clocale> #include <clocale>
#include <string>
#ifdef NO_CPP11_STRING #ifdef NO_CPP11_STRING
#include <sstream>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <stdexcept>
#include <cerrno> #include <cerrno>
#include <climits>
#include <cmath>
#include <cstdlib>
#include <sstream>
#include <stdexcept>
#endif #endif
@ -103,4 +103,3 @@ namespace cpt
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -20,8 +20,8 @@
#define TIME_DEFS_H #define TIME_DEFS_H
#include <chrono> #include <chrono>
#include <thread>
#include <sys/time.h> #include <sys/time.h>
#include <thread>
#ifdef MACOS #ifdef MACOS
#include <mach/clock.h> #include <mach/clock.h>
#include <mach/mach.h> #include <mach/mach.h>
@ -119,5 +119,3 @@ namespace chronos
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -22,34 +22,34 @@
#include "common/strCompat.h" #include "common/strCompat.h"
#include "common/utils/string_utils.h" #include "common/utils/string_utils.h"
#include <functional>
#include <cctype> #include <cctype>
#include <locale>
#include <string>
#include <cstring>
#include <vector>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <memory>
#include <cerrno> #include <cerrno>
#include <cstring>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iomanip>
#include <iterator> #include <iterator>
#include <sys/ioctl.h> #include <locale>
#include <memory>
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h> #include <sstream>
#include <string>
#include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <iomanip> #include <vector>
#ifndef FREEBSD #ifndef FREEBSD
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
#endif #endif
#include <sys/utsname.h> #include <sys/utsname.h>
#ifdef MACOS #ifdef MACOS
#include <ifaddrs.h>
#include <net/if_dl.h>
#include <IOKit/IOCFPlugIn.h> #include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOTypes.h> #include <IOKit/IOTypes.h>
#include <ifaddrs.h>
#include <net/if_dl.h>
#endif #endif
#ifdef ANDROID #ifdef ANDROID
#include <sys/system_properties.h> #include <sys/system_properties.h>
@ -186,12 +186,9 @@ static std::string generateUUID()
initialized = true; initialized = true;
} }
std::stringstream ss; std::stringstream ss;
ss << std::setfill('0') << std::hex ss << std::setfill('0') << std::hex << std::setw(4) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff) << "-" << std::setw(4)
<< std::setw(4) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff) << (std::rand() % 0xffff) << "-" << std::setw(4) << (std::rand() % 0xffff) << "-" << std::setw(4) << (std::rand() % 0xffff) << "-" << std::setw(4)
<< "-" << std::setw(4) << (std::rand() % 0xffff) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff);
<< "-" << std::setw(4) << (std::rand() % 0xffff)
<< "-" << std::setw(4) << (std::rand() % 0xffff)
<< "-" << std::setw(4) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff);
return ss.str(); return ss.str();
} }
@ -278,7 +275,9 @@ static std::string getMacAddress(int sock)
} }
} }
} }
else { /* handle error */ } else
{ /* handle error */
}
it = (struct ifreq*)((char*)it + len); it = (struct ifreq*)((char*)it + len);
i += len; i += len;
@ -289,13 +288,13 @@ static std::string getMacAddress(int sock)
char mac[19]; char mac[19];
#ifndef FREEBSD #ifndef FREEBSD
sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned char)ifr.ifr_hwaddr.sa_data[0], (unsigned char)ifr.ifr_hwaddr.sa_data[1],
(unsigned char)ifr.ifr_hwaddr.sa_data[0], (unsigned char)ifr.ifr_hwaddr.sa_data[1], (unsigned char)ifr.ifr_hwaddr.sa_data[2], (unsigned char)ifr.ifr_hwaddr.sa_data[2], (unsigned char)ifr.ifr_hwaddr.sa_data[3], (unsigned char)ifr.ifr_hwaddr.sa_data[4],
(unsigned char)ifr.ifr_hwaddr.sa_data[3], (unsigned char)ifr.ifr_hwaddr.sa_data[4], (unsigned char)ifr.ifr_hwaddr.sa_data[5]); (unsigned char)ifr.ifr_hwaddr.sa_data[5]);
#else #else
sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[0], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[1],
(unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[0], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[1], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[2], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[2], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[3],
(unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[3], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[4], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[5]); (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[4], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[5]);
#endif #endif
return mac; return mac;
} }
@ -343,5 +342,3 @@ static std::string getHostId(const std::string defaultId = "")
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,12 +19,12 @@
#ifndef FILE_UTILS_H #ifndef FILE_UTILS_H
#define FILE_UTILS_H #define FILE_UTILS_H
#include "string_utils.h"
#include <fstream>
#include <grp.h> #include <grp.h>
#include <pwd.h> #include <pwd.h>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <fstream>
#include "string_utils.h"
namespace utils namespace utils
@ -93,4 +93,3 @@ static int mkdirRecursive(const char *path, mode_t mode)
} // namespace utils } // namespace utils
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,10 +19,10 @@
#ifndef STRING_UTILS_H #ifndef STRING_UTILS_H
#define STRING_UTILS_H #define STRING_UTILS_H
#include <stdio.h>
#include <algorithm> #include <algorithm>
#include <string>
#include <sstream> #include <sstream>
#include <stdio.h>
#include <string>
#include <vector> #include <vector>
namespace utils namespace utils
@ -72,7 +72,8 @@ static inline std::string trim_copy(const std::string &s)
} }
// decode %xx to char // decode %xx to char
static std::string uriDecode(const std::string& src) { static std::string uriDecode(const std::string& src)
{
std::string ret; std::string ret;
char ch; char ch;
for (size_t i = 0; i < src.length(); i++) for (size_t i = 0; i < src.length(); i++)
@ -118,4 +119,3 @@ static std::vector<std::string> split(const std::string &s, char delim)
} // namespace utils } // namespace utils
#endif #endif

179
doc/snapcast_plain_icon.svg Normal file
View file

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="220mm"
height="220mm"
viewBox="0 0 779.52756 779.52755"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="snapcast_plain_icon.svg"
inkscape:export-filename="/home/adminuser/Desktop/drawing.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffc107"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="0.70710678"
inkscape:cx="379.04793"
inkscape:cy="415.07164"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-page="true"
inkscape:snap-grids="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
inkscape:window-width="1440"
inkscape:window-height="847"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
borderlayer="false"
inkscape:showpageshadow="true" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-272.83465)">
<path
style="fill:#c8c8c8;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:33.33300018;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 500.92383 225.22852 L 386.56445 324.14062 L 278.33008 324.14062 L 278.33008 451.42773 L 384.92383 451.42773 L 500.92383 551.76758 L 500.92383 225.22852 z "
transform="translate(0,272.83462)"
id="polygon1-3" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="360.297"
sodipodi:ry="360.297"
sodipodi:start="5.7595865"
sodipodi:end="0.52359878"
d="m 701.65376,483.21367 a 360.297,360.297 0 0 1 0,360.29701"
sodipodi:open="true" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353-6"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="299.98151"
sodipodi:ry="299.98151"
sodipodi:start="5.8119464"
sodipodi:end="0.4712389"
d="m 656.91289,527.17343 a 299.98151,299.98151 0 0 1 0,272.37751"
sodipodi:open="true" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353-6-5"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="240.16534"
sodipodi:ry="240.16534"
sodipodi:start="5.8643063"
sodipodi:end="0.41887902"
d="m 609.02937,565.67814 a 240.16534,240.16534 0 0 1 0,195.36809"
sodipodi:open="true" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353-1"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="360.297"
sodipodi:ry="360.297"
sodipodi:start="3.6651914"
sodipodi:end="4.712389"
d="M 77.601053,483.21369 A 360.297,360.297 0 0 1 389.62742,303.06519"
sodipodi:open="true" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353-6-2"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="299.98151"
sodipodi:ry="299.98151"
sodipodi:start="3.7175513"
sodipodi:end="4.6600291"
d="M 138.04175,499.98055 A 299.98151,299.98151 0 0 1 373.92759,363.79179"
sodipodi:open="true" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353-6-5-7"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="240.16534"
sodipodi:ry="240.16534"
sodipodi:start="3.7699112"
sodipodi:end="4.6076692"
d="M 195.32957,522.19653 A 240.16534,240.16534 0 0 1 364.52329,424.51249"
sodipodi:open="true" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353-1-6"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="360.297"
sodipodi:ry="360.297"
sodipodi:start="1.5707963"
sodipodi:end="2.6179939"
d="M 389.62742,1023.6592 A 360.297,360.297 0 0 1 77.601055,843.51067"
sodipodi:open="true" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353-6-2-0"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="299.98151"
sodipodi:ry="299.98151"
sodipodi:start="1.6231562"
sodipodi:end="2.565634"
d="M 373.92759,962.93257 A 299.98151,299.98151 0 0 1 138.04175,826.74382"
sodipodi:open="true" />
<path
style="fill:#000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:35;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:0"
id="path3353-6-5-7-6"
sodipodi:type="arc"
sodipodi:cx="389.62741"
sodipodi:cy="663.36218"
sodipodi:rx="240.16534"
sodipodi:ry="240.16534"
sodipodi:start="1.6755161"
sodipodi:end="2.5132741"
d="M 364.52329,902.21188 A 240.16534,240.16534 0 0 1 195.32957,804.52783"
sodipodi:open="true" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

2
externals/Makefile vendored
View file

@ -1,5 +1,5 @@
# This file is part of snapcast # This file is part of snapcast
# Copyright (C) 2014-2018 Johannes Pohl # Copyright (C) 2014-2019 Johannes Pohl
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by

View file

@ -1,5 +1,5 @@
# This file is part of snapcast # This file is part of snapcast
# Copyright (C) 2014-2018 Johannes Pohl # Copyright (C) 2014-2019 Johannes Pohl
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,15 +17,15 @@
***/ ***/
#include "config.h" #include "config.h"
#include <sys/types.h> #include "aixlog.hpp"
#include <sys/stat.h>
#include <fcntl.h>
#include <fstream>
#include <cerrno>
#include "common/snapException.h" #include "common/snapException.h"
#include "common/strCompat.h" #include "common/strCompat.h"
#include "common/utils/file_utils.h" #include "common/utils/file_utils.h"
#include "aixlog.hpp" #include <cerrno>
#include <fcntl.h>
#include <fstream>
#include <sys/stat.h>
#include <sys/types.h>
using namespace std; using namespace std;
@ -120,10 +120,7 @@ void Config::save()
if (filename_.empty()) if (filename_.empty())
init(); init();
std::ofstream ofs(filename_.c_str(), std::ofstream::out | std::ofstream::trunc); std::ofstream ofs(filename_.c_str(), std::ofstream::out | std::ofstream::trunc);
json clients = { json clients = {{"ConfigVersion", 2}, {"Groups", getGroups()}};
{"ConfigVersion", 2},
{"Groups", getGroups()}
};
ofs << std::setw(4) << clients; ofs << std::setw(4) << clients;
ofs.close(); ofs.close();
} }
@ -207,14 +204,11 @@ json Config::getServerStatus(const json& streams) const
host.update(); host.update();
// TODO: Set MAC and IP // TODO: Set MAC and IP
Snapserver snapserver("Snapserver", VERSION); Snapserver snapserver("Snapserver", VERSION);
json serverStatus = { json serverStatus = {{"server",
{"server", { {{"host", host.toJson()}, // getHostName()},
{"host", host.toJson()},//getHostName()}, {"snapserver", snapserver.toJson()}}},
{"snapserver", snapserver.toJson()}
}},
{"groups", getGroups()}, {"groups", getGroups()},
{"streams", streams} {"streams", streams}};
};
return serverStatus; return serverStatus;
} }
@ -287,5 +281,3 @@ GroupPtr Config::setGroupForClient(const std::string& groupId, const std::string
return newGroup; return newGroup;
} }
*/ */

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,14 +19,14 @@
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
#include <string>
#include <memory> #include <memory>
#include <vector> #include <string>
#include <sys/time.h> #include <sys/time.h>
#include <vector>
#include "common/json.hpp" #include "common/json.hpp"
#include "common/utils/string_utils.h"
#include "common/utils.h" #include "common/utils.h"
#include "common/utils/string_utils.h"
namespace strutils = utils::string; namespace strutils = utils::string;

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,13 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include "jsonrpcpp.hpp"
#include "controlServer.h" #include "controlServer.h"
#include "message/time.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/utils.h"
#include "common/snapException.h" #include "common/snapException.h"
#include "common/utils.h"
#include "config.h" #include "config.h"
#include "jsonrpcpp.hpp"
#include "message/time.h"
#include <iostream> #include <iostream>
using namespace std; using namespace std;
@ -30,12 +30,8 @@ using namespace std;
using json = nlohmann::json; using json = nlohmann::json;
ControlServer::ControlServer(asio::io_service* io_service, size_t port, ControlMessageReceiver* controlMessageReceiver) : ControlServer::ControlServer(asio::io_service* io_service, size_t port, ControlMessageReceiver* controlMessageReceiver)
acceptor_v4_(nullptr), : acceptor_v4_(nullptr), acceptor_v6_(nullptr), io_service_(io_service), port_(port), controlMessageReceiver_(controlMessageReceiver)
acceptor_v6_(nullptr),
io_service_(io_service),
port_(port),
controlMessageReceiver_(controlMessageReceiver)
{ {
} }
@ -199,4 +195,3 @@ void ControlServer::stop()
for (auto s : sessions_) for (auto s : sessions_)
s->stop(); s->stop();
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -20,18 +20,18 @@
#define CONTROL_SERVER_H #define CONTROL_SERVER_H
#include <asio.hpp> #include <asio.hpp>
#include <vector>
#include <thread>
#include <memory> #include <memory>
#include <mutex>
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <mutex> #include <thread>
#include <vector>
#include "controlSession.h"
#include "common/queue.h" #include "common/queue.h"
#include "common/sampleFormat.h" #include "common/sampleFormat.h"
#include "message/message.h" #include "controlSession.h"
#include "message/codecHeader.h" #include "message/codecHeader.h"
#include "message/message.h"
#include "message/serverSettings.h" #include "message/serverSettings.h"
@ -77,5 +77,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,18 +16,17 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <iostream>
#include <mutex>
#include "controlSession.h" #include "controlSession.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "message/pcmChunk.h" #include "message/pcmChunk.h"
#include <iostream>
#include <mutex>
using namespace std; using namespace std;
ControlSession::ControlSession(ControlMessageReceiver* receiver, std::shared_ptr<tcp::socket> socket) : ControlSession::ControlSession(ControlMessageReceiver* receiver, std::shared_ptr<tcp::socket> socket) : active_(false), messageReceiver_(receiver)
active_(false), messageReceiver_(receiver)
{ {
socket_ = socket; socket_ = socket;
} }
@ -62,9 +61,11 @@ void ControlSession::stop()
{ {
std::lock_guard<std::recursive_mutex> socketLock(socketMutex_); std::lock_guard<std::recursive_mutex> socketLock(socketMutex_);
socket_->shutdown(asio::ip::tcp::socket::shutdown_both, ec); socket_->shutdown(asio::ip::tcp::socket::shutdown_both, ec);
if (ec) LOG(ERROR) << "Error in socket shutdown: " << ec.message() << "\n"; if (ec)
LOG(ERROR) << "Error in socket shutdown: " << ec.message() << "\n";
socket_->close(ec); socket_->close(ec);
if (ec) LOG(ERROR) << "Error in socket close: " << ec.message() << "\n"; if (ec)
LOG(ERROR) << "Error in socket close: " << ec.message() << "\n";
} }
if (readerThread_.joinable()) if (readerThread_.joinable())
{ {
@ -170,5 +171,3 @@ void ControlSession::writer()
} }
active_ = false; active_ = false;
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,16 +19,16 @@
#ifndef CONTROL_SESSION_H #ifndef CONTROL_SESSION_H
#define CONTROL_SESSION_H #define CONTROL_SESSION_H
#include "common/queue.h"
#include "message/message.h"
#include <asio.hpp>
#include <atomic>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <set>
#include <string> #include <string>
#include <thread> #include <thread>
#include <atomic>
#include <mutex>
#include <memory>
#include <asio.hpp>
#include <condition_variable>
#include <set>
#include "message/message.h"
#include "common/queue.h"
using asio::ip::tcp; using asio::ip::tcp;
@ -87,9 +87,4 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,12 +19,12 @@
#ifndef ENCODER_H #ifndef ENCODER_H
#define ENCODER_H #define ENCODER_H
#include <string>
#include <memory> #include <memory>
#include <string>
#include "message/pcmChunk.h"
#include "message/codecHeader.h"
#include "common/sampleFormat.h" #include "common/sampleFormat.h"
#include "message/codecHeader.h"
#include "message/pcmChunk.h"
class Encoder; class Encoder;
@ -100,5 +100,3 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -24,9 +24,9 @@
#if defined(HAS_FLAC) #if defined(HAS_FLAC)
#include "flacEncoder.h" #include "flacEncoder.h"
#endif #endif
#include "common/utils/string_utils.h"
#include "common/snapException.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/snapException.h"
#include "common/utils/string_utils.h"
using namespace std; using namespace std;
@ -69,6 +69,3 @@ Encoder* EncoderFactory::createEncoder(const std::string& codecSettings) const
} }
*/ */
} }

View file

@ -1,8 +1,8 @@
#ifndef ENCODER_FACTORY_H #ifndef ENCODER_FACTORY_H
#define ENCODER_FACTORY_H #define ENCODER_FACTORY_H
#include <string>
#include "encoder.h" #include "encoder.h"
#include <string>
class EncoderFactory class EncoderFactory
{ {

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,10 +18,10 @@
#include <iostream> #include <iostream>
#include "flacEncoder.h"
#include "common/strCompat.h"
#include "common/snapException.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/snapException.h"
#include "common/strCompat.h"
#include "flacEncoder.h"
using namespace std; using namespace std;
@ -71,7 +71,8 @@ void FlacEncoder::encode(const msg::PcmChunk* chunk)
{ {
int samples = chunk->getSampleCount(); int samples = chunk->getSampleCount();
int frames = chunk->getFrameCount(); int frames = chunk->getFrameCount();
// LOG(INFO) << "payload: " << chunk->payloadSize << "\tframes: " << frames << "\tsamples: " << samples << "\tduration: " << chunk->duration<chronos::msec>().count() << "\n"; // LOG(INFO) << "payload: " << chunk->payloadSize << "\tframes: " << frames << "\tsamples: " << samples << "\tduration: " <<
//chunk->duration<chronos::msec>().count() << "\n";
if (pcmBufferSize_ < samples) if (pcmBufferSize_ < samples)
{ {
@ -112,10 +113,7 @@ void FlacEncoder::encode(const msg::PcmChunk* chunk)
} }
FLAC__StreamEncoderWriteStatus FlacEncoder::write_callback(const FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteStatus FlacEncoder::write_callback(const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples,
const FLAC__byte buffer[],
size_t bytes,
unsigned samples,
unsigned current_frame) unsigned current_frame)
{ {
// LOG(INFO) << "write_callback: " << bytes << ", " << samples << ", " << current_frame << "\n"; // LOG(INFO) << "write_callback: " << bytes << ", " << samples << ", " << current_frame << "\n";
@ -136,12 +134,8 @@ FLAC__StreamEncoderWriteStatus FlacEncoder::write_callback(const FLAC__StreamEnc
} }
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples,
const FLAC__byte buffer[], unsigned current_frame, void* client_data)
size_t bytes,
unsigned samples,
unsigned current_frame,
void *client_data)
{ {
FlacEncoder* flacEncoder = (FlacEncoder*)client_data; FlacEncoder* flacEncoder = (FlacEncoder*)client_data;
return flacEncoder->write_callback(encoder, buffer, bytes, samples, current_frame); return flacEncoder->write_callback(encoder, buffer, bytes, samples, current_frame);
@ -187,15 +181,13 @@ void FlacEncoder::initEncoder()
throw SnapException("error setting up encoder"); throw SnapException("error setting up encoder");
// now add some metadata; we'll add some tags and a padding block // now add some metadata; we'll add some tags and a padding block
if ( if ((metadata_[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL ||
(metadata_[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL ||
(metadata_[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL || (metadata_[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL ||
// there are many tag (vorbiscomment) functions but these are convenient for this particular use: // there are many tag (vorbiscomment) functions but these are convenient for this particular use:
!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TITLE", "SnapStream") || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TITLE", "SnapStream") ||
!FLAC__metadata_object_vorbiscomment_append_comment(metadata_[0], entry, false) || !FLAC__metadata_object_vorbiscomment_append_comment(metadata_[0], entry, false) ||
!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "VERSION", VERSION) || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "VERSION", VERSION) ||
!FLAC__metadata_object_vorbiscomment_append_comment(metadata_[0], entry, false) !FLAC__metadata_object_vorbiscomment_append_comment(metadata_[0], entry, false))
)
throw SnapException("out of memory or tag error"); throw SnapException("out of memory or tag error");
metadata_[1]->length = 1234; // set the padding length metadata_[1]->length = 1234; // set the padding length
@ -208,4 +200,3 @@ void FlacEncoder::initEncoder()
if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
throw SnapException("ERROR: initializing encoder: " + string(FLAC__StreamEncoderInitStatusString[init_status])); throw SnapException("ERROR: initializing encoder: " + string(FLAC__StreamEncoderInitStatusString[init_status]));
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -37,7 +37,8 @@ public:
virtual std::string getDefaultOptions() const; virtual std::string getDefaultOptions() const;
virtual std::string name() const; virtual std::string name() const;
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame); FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples,
unsigned current_frame);
protected: protected:
virtual void initEncoder(); virtual void initEncoder();
@ -54,5 +55,3 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,15 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <iostream>
#include <cstring> #include <cstring>
#include <iostream>
#include "oggEncoder.h" #include "aixlog.hpp"
#include "common/snapException.h" #include "common/snapException.h"
#include "common/strCompat.h" #include "common/strCompat.h"
#include "common/utils/string_utils.h"
#include "common/utils.h" #include "common/utils.h"
#include "aixlog.hpp" #include "common/utils/string_utils.h"
#include "oggEncoder.h"
using namespace std; using namespace std;
@ -55,7 +55,8 @@ std::string OggEncoder::name() const
void OggEncoder::encode(const msg::PcmChunk* chunk) void OggEncoder::encode(const msg::PcmChunk* chunk)
{ {
double res = 0; double res = 0;
LOG(DEBUG) << "payload: " << chunk->payloadSize << "\tframes: " << chunk->getFrameCount() << "\tduration: " << chunk->duration<chronos::msec>().count() << "\n"; LOG(DEBUG) << "payload: " << chunk->payloadSize << "\tframes: " << chunk->getFrameCount() << "\tduration: " << chunk->duration<chronos::msec>().count()
<< "\n";
int frames = chunk->getFrameCount(); int frames = chunk->getFrameCount();
float** buffer = vorbis_analysis_buffer(&vd_, frames); float** buffer = vorbis_analysis_buffer(&vd_, frames);
@ -256,5 +257,3 @@ void OggEncoder::initEncoder()
pos += og_.body_len; pos += og_.body_len;
} }
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,8 +19,8 @@
#ifndef OGG_ENCODER_H #ifndef OGG_ENCODER_H
#define OGG_ENCODER_H #define OGG_ENCODER_H
#include "encoder.h" #include "encoder.h"
#include <vorbis/vorbisenc.h>
#include <ogg/ogg.h> #include <ogg/ogg.h>
#include <vorbis/vorbisenc.h>
class OggEncoder : public Encoder class OggEncoder : public Encoder
{ {
@ -50,5 +50,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,9 +16,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <memory>
#include "common/endian.hpp"
#include "pcmEncoder.h" #include "pcmEncoder.h"
#include "common/endian.hpp"
#include <memory>
#define ID_RIFF 0x46464952 #define ID_RIFF 0x46464952
@ -65,5 +65,3 @@ std::string PcmEncoder::name() const
{ {
return "pcm"; return "pcm";
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -41,5 +41,3 @@ protected:
#endif #endif

View file

@ -17,18 +17,17 @@
USA. USA.
***/ ***/
#include <cstdio>
#include <cstdlib>
#include "publishAvahi.h" #include "publishAvahi.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include <cstdio>
#include <cstdlib>
static AvahiEntryGroup* group; static AvahiEntryGroup* group;
static AvahiSimplePoll* simple_poll; static AvahiSimplePoll* simple_poll;
static char* name; static char* name;
PublishAvahi::PublishAvahi(const std::string& serviceName) : PublishmDNS(serviceName), PublishAvahi::PublishAvahi(const std::string& serviceName) : PublishmDNS(serviceName), client_(NULL), active_(false)
client_(NULL), active_(false)
{ {
group = NULL; group = NULL;
simple_poll = NULL; simple_poll = NULL;
@ -64,7 +63,8 @@ void PublishAvahi::publish(const std::vector<mDNSService>& services)
void PublishAvahi::worker() void PublishAvahi::worker()
{ {
while (active_ && (avahi_simple_poll_iterate(simple_poll, 100) == 0)); while (active_ && (avahi_simple_poll_iterate(simple_poll, 100) == 0))
;
} }
@ -121,8 +121,7 @@ void PublishAvahi::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState
break; break;
case AVAHI_ENTRY_GROUP_UNCOMMITED: case AVAHI_ENTRY_GROUP_UNCOMMITED:
case AVAHI_ENTRY_GROUP_REGISTERING: case AVAHI_ENTRY_GROUP_REGISTERING:;
;
} }
} }
@ -150,7 +149,8 @@ void PublishAvahi::create_services(AvahiClient *c)
/// We will now add two services and one subtype to the entry group /// We will now add two services and one subtype to the entry group
for (const auto& service : services_) for (const auto& service : services_)
{ {
if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, service.name_.c_str(), NULL, NULL, service.port_, NULL)) < 0) if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, service.name_.c_str(), NULL, NULL,
service.port_, NULL)) < 0)
{ {
if (ret == AVAHI_ERR_COLLISION) if (ret == AVAHI_ERR_COLLISION)
goto collision; goto collision;
@ -161,7 +161,8 @@ void PublishAvahi::create_services(AvahiClient *c)
} }
/// Add an additional (hypothetic) subtype /// Add an additional (hypothetic) subtype
/* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp", NULL, "_magic._sub._printer._tcp") < 0)) /* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp",
NULL, "_magic._sub._printer._tcp") < 0))
{ {
fprintf(stderr, "Failed to add subtype _magic._sub._printer._tcp: %s\n", avahi_strerror(ret)); fprintf(stderr, "Failed to add subtype _magic._sub._printer._tcp: %s\n", avahi_strerror(ret));
goto fail; goto fail;
@ -229,10 +230,6 @@ void PublishAvahi::client_callback(AvahiClient *c, AvahiClientState state, AVAHI
avahi_entry_group_reset(group); avahi_entry_group_reset(group);
break; break;
case AVAHI_CLIENT_CONNECTING: case AVAHI_CLIENT_CONNECTING:;
;
} }
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -23,15 +23,15 @@
#include <avahi-client/client.h> #include <avahi-client/client.h>
#include <avahi-client/publish.h> #include <avahi-client/publish.h>
#include <atomic>
#include <avahi-common/alternative.h> #include <avahi-common/alternative.h>
#include <avahi-common/simple-watch.h>
#include <avahi-common/malloc.h>
#include <avahi-common/error.h> #include <avahi-common/error.h>
#include <avahi-common/malloc.h>
#include <avahi-common/simple-watch.h>
#include <avahi-common/timeval.h> #include <avahi-common/timeval.h>
#include <string> #include <string>
#include <vector>
#include <thread> #include <thread>
#include <atomic> #include <vector>
class PublishAvahi; class PublishAvahi;
@ -57,5 +57,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,10 +19,13 @@
#include <cstdlib> #include <cstdlib>
#include <thread> #include <thread>
#include "publishBonjour.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "publishBonjour.h"
typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16; typedef union {
unsigned char b[2];
unsigned short NotAnInteger;
} Opaque16;
PublishBonjour::PublishBonjour(const std::string& serviceName) : PublishmDNS(serviceName), active_(false) PublishBonjour::PublishBonjour(const std::string& serviceName) : PublishmDNS(serviceName), active_(false)
@ -108,7 +111,8 @@ void PublishBonjour::worker()
} }
static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode, const char* name, const char* regtype,
const char* domain, void* context)
{ {
(void)sdref; // Unused (void)sdref; // Unused
(void)flags; // Unused (void)flags; // Unused
@ -146,14 +150,12 @@ void PublishBonjour::publish(const std::vector<mDNSService>& services)
DNSServiceFlags flags = 0; DNSServiceFlags flags = 0;
Opaque16 registerPort = {{static_cast<unsigned char>(service.port_ >> 8), static_cast<unsigned char>(service.port_ & 0xFF)}}; Opaque16 registerPort = {{static_cast<unsigned char>(service.port_ >> 8), static_cast<unsigned char>(service.port_ & 0xFF)}};
DNSServiceRef client = NULL; DNSServiceRef client = NULL;
// DNSServiceRegister(&client, flags, kDNSServiceInterfaceIndexAny, serviceName_.c_str(), service.name_.c_str(), NULL, NULL, registerPort.NotAnInteger, service.txt_.size(), service.txt_.empty()?NULL:service.txt_.c_str(), reg_reply, this); // DNSServiceRegister(&client, flags, kDNSServiceInterfaceIndexAny, serviceName_.c_str(), service.name_.c_str(), NULL, NULL,
DNSServiceRegister(&client, flags, kDNSServiceInterfaceIndexAny, serviceName_.c_str(), service.name_.c_str(), NULL, NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, this); //registerPort.NotAnInteger, service.txt_.size(), service.txt_.empty()?NULL:service.txt_.c_str(), reg_reply, this);
DNSServiceRegister(&client, flags, kDNSServiceInterfaceIndexAny, serviceName_.c_str(), service.name_.c_str(), NULL, NULL, registerPort.NotAnInteger, 0,
NULL, reg_reply, this);
clients.push_back(client); clients.push_back(client);
} }
pollThread_ = std::thread(&PublishBonjour::worker, this); pollThread_ = std::thread(&PublishBonjour::worker, this);
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -20,8 +20,8 @@
#ifndef PUBLISH_BONJOUR_H #ifndef PUBLISH_BONJOUR_H
#define PUBLISH_BONJOUR_H #define PUBLISH_BONJOUR_H
#include <string>
#include <dns_sd.h> #include <dns_sd.h>
#include <string>
class PublishBonjour; class PublishBonjour;
@ -43,5 +43,3 @@ private:
#endif #endif

0
server/publishZeroConf/publishmDNS.h Executable file → Normal file
View file

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -24,19 +24,19 @@
#ifdef HAS_DAEMON #ifdef HAS_DAEMON
#include "common/daemon.h" #include "common/daemon.h"
#endif #endif
#include "common/timeDefs.h" #include "common/sampleFormat.h"
#include "common/utils/string_utils.h"
#include "common/signalHandler.h" #include "common/signalHandler.h"
#include "common/snapException.h" #include "common/snapException.h"
#include "common/sampleFormat.h" #include "common/timeDefs.h"
#include "message/message.h" #include "common/utils/string_utils.h"
#include "encoder/encoderFactory.h" #include "encoder/encoderFactory.h"
#include "message/message.h"
#include "streamServer.h" #include "streamServer.h"
#if defined(HAS_AVAHI) || defined(HAS_BONJOUR) #if defined(HAS_AVAHI) || defined(HAS_BONJOUR)
#include "publishZeroConf/publishmDNS.h" #include "publishZeroConf/publishmDNS.h"
#endif #endif
#include "config.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "config.h"
volatile sig_atomic_t g_terminated = false; volatile sig_atomic_t g_terminated = false;
@ -65,10 +65,13 @@ int main(int argc, char* argv[])
auto versionSwitch = op.add<Switch>("v", "version", "Show version number"); auto versionSwitch = op.add<Switch>("v", "version", "Show version number");
/*auto portValue =*/op.add<Value<size_t>>("p", "port", "Server port", settings.port, &settings.port); /*auto portValue =*/op.add<Value<size_t>>("p", "port", "Server port", settings.port, &settings.port);
/*auto controlPortValue =*/op.add<Value<size_t>>("", "controlPort", "Remote control port", settings.controlPort, &settings.controlPort); /*auto controlPortValue =*/op.add<Value<size_t>>("", "controlPort", "Remote control port", settings.controlPort, &settings.controlPort);
auto streamValue = op.add<Value<string>>("s", "stream", "URI of the PCM input stream.\nFormat: TYPE://host/path?name=NAME\n[&codec=CODEC]\n[&sampleformat=SAMPLEFORMAT]", pcmStream, &pcmStream); auto streamValue = op.add<Value<string>>(
"s", "stream", "URI of the PCM input stream.\nFormat: TYPE://host/path?name=NAME\n[&codec=CODEC]\n[&sampleformat=SAMPLEFORMAT]", pcmStream,
&pcmStream);
/*auto sampleFormatValue =*/op.add<Value<string>>("", "sampleformat", "Default sample format", settings.sampleFormat, &settings.sampleFormat); /*auto sampleFormatValue =*/op.add<Value<string>>("", "sampleformat", "Default sample format", settings.sampleFormat, &settings.sampleFormat);
/*auto codecValue =*/ op.add<Value<string>>("c", "codec", "Default transport codec\n(flac|ogg|pcm)[:options]\nType codec:? to get codec specific options", settings.codec, &settings.codec); /*auto codecValue =*/op.add<Value<string>>(
"c", "codec", "Default transport codec\n(flac|ogg|pcm)[:options]\nType codec:? to get codec specific options", settings.codec, &settings.codec);
/*auto streamBufferValue =*/op.add<Value<size_t>>("", "streamBuffer", "Default stream read buffer [ms]", settings.streamReadMs, &settings.streamReadMs); /*auto streamBufferValue =*/op.add<Value<size_t>>("", "streamBuffer", "Default stream read buffer [ms]", settings.streamReadMs, &settings.streamReadMs);
/*auto bufferValue =*/op.add<Value<int>>("b", "buffer", "Buffer [ms]", settings.bufferMs, &settings.bufferMs); /*auto bufferValue =*/op.add<Value<int>>("b", "buffer", "Buffer [ms]", settings.bufferMs, &settings.bufferMs);
/*auto muteSwitch =*/op.add<Switch>("", "sendToMuted", "Send audio to muted clients", &settings.sendAudioToMutedClients); /*auto muteSwitch =*/op.add<Switch>("", "sendToMuted", "Send audio to muted clients", &settings.sendAudioToMutedClients);
@ -140,7 +143,8 @@ int main(int argc, char* argv[])
{ {
AixLog::Log::instance().add_logsink<AixLog::SinkCout>(AixLog::Severity::trace, AixLog::Type::all, "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)"); AixLog::Log::instance().add_logsink<AixLog::SinkCout>(AixLog::Severity::trace, AixLog::Type::all, "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)");
if (!debugOption->value().empty()) if (!debugOption->value().empty())
AixLog::Log::instance().add_logsink<AixLog::SinkFile>(AixLog::Severity::trace, AixLog::Type::all, debugOption->value(), "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)"); AixLog::Log::instance().add_logsink<AixLog::SinkFile>(AixLog::Severity::trace, AixLog::Type::all, debugOption->value(),
"%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)");
} }
else else
{ {
@ -190,11 +194,8 @@ int main(int argc, char* argv[])
#if defined(HAS_AVAHI) || defined(HAS_BONJOUR) #if defined(HAS_AVAHI) || defined(HAS_BONJOUR)
PublishZeroConf publishZeroConfg("Snapcast"); PublishZeroConf publishZeroConfg("Snapcast");
publishZeroConfg.publish({ publishZeroConfg.publish({mDNSService("_snapcast._tcp", settings.port), mDNSService("_snapcast-jsonrpc._tcp", settings.controlPort),
mDNSService("_snapcast._tcp", settings.port), mDNSService("_snapcastjsonrpc._tcp", settings.controlPort)});
mDNSService("_snapcast-jsonrpc._tcp", settings.controlPort),
mDNSService("_snapcastjsonrpc._tcp", settings.controlPort)
});
#endif #endif
if (settings.bufferMs < 400) if (settings.bufferMs < 400)
@ -226,4 +227,3 @@ int main(int argc, char* argv[])
SLOG(NOTICE) << "daemon terminated." << endl; SLOG(NOTICE) << "daemon terminated." << endl;
exit(exitcode); exit(exitcode);
} }

View file

@ -17,11 +17,11 @@
***/ ***/
#include "streamServer.h" #include "streamServer.h"
#include "message/time.h"
#include "message/hello.h"
#include "message/streamTags.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "config.h" #include "config.h"
#include "message/hello.h"
#include "message/streamTags.h"
#include "message/time.h"
#include <iostream> #include <iostream>
using namespace std; using namespace std;
@ -29,11 +29,8 @@ using namespace std;
using json = nlohmann::json; using json = nlohmann::json;
StreamServer::StreamServer(asio::io_service* io_service, const StreamServerSettings& streamServerSettings) : StreamServer::StreamServer(asio::io_service* io_service, const StreamServerSettings& streamServerSettings)
io_service_(io_service), : io_service_(io_service), acceptor_v4_(nullptr), acceptor_v6_(nullptr), settings_(streamServerSettings)
acceptor_v4_(nullptr),
acceptor_v6_(nullptr),
settings_(streamServerSettings)
{ {
} }
@ -45,7 +42,8 @@ StreamServer::~StreamServer()
void StreamServer::onMetaChanged(const PcmStream* pcmStream) void StreamServer::onMetaChanged(const PcmStream* pcmStream)
{ {
/// Notification: {"jsonrpc":"2.0","method":"Stream.OnMetadata","params":{"id":"stream 1", "meta": {"album": "some album", "artist": "some artist", "track": "some track"...}} /// Notification: {"jsonrpc":"2.0","method":"Stream.OnMetadata","params":{"id":"stream 1", "meta": {"album": "some album", "artist": "some artist", "track":
/// "some track"...}}
// Send meta to all connected clients // Send meta to all connected clients
const auto meta = pcmStream->getMeta(); const auto meta = pcmStream->getMeta();
@ -65,7 +63,9 @@ void StreamServer::onMetaChanged(const PcmStream* pcmStream)
void StreamServer::onStateChanged(const PcmStream* pcmStream, const ReaderState& state) void StreamServer::onStateChanged(const PcmStream* pcmStream, const ReaderState& state)
{ {
/// Notification: {"jsonrpc":"2.0","method":"Stream.OnUpdate","params":{"id":"stream 1","stream":{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}}}} /// Notification: {"jsonrpc":"2.0","method":"Stream.OnUpdate","params":{"id":"stream 1","stream":{"id":"stream
/// 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}}}}
LOG(INFO) << "onStateChanged (" << pcmStream->getName() << "): " << state << "\n"; LOG(INFO) << "onStateChanged (" << pcmStream->getName() << "): " << state << "\n";
// LOG(INFO) << pcmStream->toJson().dump(4); // LOG(INFO) << pcmStream->toJson().dump(4);
json notification = jsonrpcpp::Notification("Stream.OnUpdate", jsonrpcpp::Parameter("id", pcmStream->getId(), "stream", pcmStream->toJson())).to_json(); json notification = jsonrpcpp::Notification("Stream.OnUpdate", jsonrpcpp::Parameter("id", pcmStream->getId(), "stream", pcmStream->toJson())).to_json();
@ -144,8 +144,12 @@ void StreamServer::onDisconnect(StreamSession* streamSession)
/// in case of a duplicate client id /// in case of a duplicate client id
if (getStreamSession(clientInfo->id) == nullptr) if (getStreamSession(clientInfo->id) == nullptr)
{ {
/// Notification: {"jsonrpc":"2.0","method":"Client.OnDisconnect","params":{"client":{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":81}},"connected":false,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025523,"usec":814067},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},"id":"00:21:6a:7d:74:fc"}} /// Notification:
json notification = jsonrpcpp::Notification("Client.OnDisconnect", jsonrpcpp::Parameter("id", clientInfo->id, "client", clientInfo->toJson())).to_json(); /// {"jsonrpc":"2.0","method":"Client.OnDisconnect","params":{"client":{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":81}},"connected":false,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025523,"usec":814067},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},"id":"00:21:6a:7d:74:fc"}}
json notification =
jsonrpcpp::Notification("Client.OnDisconnect", jsonrpcpp::Parameter("id", clientInfo->id, "client", clientInfo->toJson())).to_json();
controlServer_->send(notification.dump()); controlServer_->send(notification.dump());
////cout << "Notification: " << notification.dump() << "\n"; ////cout << "Notification: " << notification.dump() << "\n";
} }
@ -169,7 +173,10 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
if (request->method() == "Client.GetStatus") if (request->method() == "Client.GetStatus")
{ {
/// Request: {"id":8,"jsonrpc":"2.0","method":"Client.GetStatus","params":{"id":"00:21:6a:7d:74:fc"}} /// Request: {"id":8,"jsonrpc":"2.0","method":"Client.GetStatus","params":{"id":"00:21:6a:7d:74:fc"}}
/// Response: {"id":8,"jsonrpc":"2.0","result":{"client":{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":74}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488026416,"usec":135973},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}}} /// Response:
/// {"id":8,"jsonrpc":"2.0","result":{"client":{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":74}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488026416,"usec":135973},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}}}
result["client"] = clientInfo->toJson(); result["client"] = clientInfo->toJson();
} }
else if (request->method() == "Client.SetVolume") else if (request->method() == "Client.SetVolume")
@ -179,7 +186,8 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
/// Notification: {"jsonrpc":"2.0","method":"Client.OnVolumeChanged","params":{"id":"00:21:6a:7d:74:fc","volume":{"muted":false,"percent":74}}} /// Notification: {"jsonrpc":"2.0","method":"Client.OnVolumeChanged","params":{"id":"00:21:6a:7d:74:fc","volume":{"muted":false,"percent":74}}}
clientInfo->config.volume.fromJson(request->params().get("volume")); clientInfo->config.volume.fromJson(request->params().get("volume"));
result["volume"] = clientInfo->config.volume.toJson(); result["volume"] = clientInfo->config.volume.toJson();
notification.reset(new jsonrpcpp::Notification("Client.OnVolumeChanged", jsonrpcpp::Parameter("id", clientInfo->id, "volume", clientInfo->config.volume.toJson()))); notification.reset(new jsonrpcpp::Notification("Client.OnVolumeChanged",
jsonrpcpp::Parameter("id", clientInfo->id, "volume", clientInfo->config.volume.toJson())));
} }
else if (request->method() == "Client.SetLatency") else if (request->method() == "Client.SetLatency")
{ {
@ -193,7 +201,8 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
latency = settings_.bufferMs; latency = settings_.bufferMs;
clientInfo->config.latency = latency; //, -10000, settings_.bufferMs); clientInfo->config.latency = latency; //, -10000, settings_.bufferMs);
result["latency"] = clientInfo->config.latency; result["latency"] = clientInfo->config.latency;
notification.reset(new jsonrpcpp::Notification("Client.OnLatencyChanged", jsonrpcpp::Parameter("id", clientInfo->id, "latency", clientInfo->config.latency))); notification.reset(
new jsonrpcpp::Notification("Client.OnLatencyChanged", jsonrpcpp::Parameter("id", clientInfo->id, "latency", clientInfo->config.latency)));
} }
else if (request->method() == "Client.SetName") else if (request->method() == "Client.SetName")
{ {
@ -202,7 +211,8 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
/// Notification: {"jsonrpc":"2.0","method":"Client.OnNameChanged","params":{"id":"00:21:6a:7d:74:fc#2","name":"Laptop"}} /// Notification: {"jsonrpc":"2.0","method":"Client.OnNameChanged","params":{"id":"00:21:6a:7d:74:fc#2","name":"Laptop"}}
clientInfo->config.name = request->params().get<std::string>("name"); clientInfo->config.name = request->params().get<std::string>("name");
result["name"] = clientInfo->config.name; result["name"] = clientInfo->config.name;
notification.reset(new jsonrpcpp::Notification("Client.OnNameChanged", jsonrpcpp::Parameter("id", clientInfo->id, "name", clientInfo->config.name))); notification.reset(
new jsonrpcpp::Notification("Client.OnNameChanged", jsonrpcpp::Parameter("id", clientInfo->id, "name", clientInfo->config.name)));
} }
else else
throw jsonrpcpp::MethodNotFoundException(request->id()); throw jsonrpcpp::MethodNotFoundException(request->id());
@ -233,7 +243,13 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
if (request->method() == "Group.GetStatus") if (request->method() == "Group.GetStatus")
{ {
/// Request: {"id":5,"jsonrpc":"2.0","method":"Group.GetStatus","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1"}} /// Request: {"id":5,"jsonrpc":"2.0","method":"Group.GetStatus","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1"}}
/// Response: {"id":5,"jsonrpc":"2.0","result":{"group":{"clients":[{"config":{"instance":2,"latency":10,"name":"Laptop","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488026485,"usec":644997},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":74}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488026481,"usec":223747},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":true,"name":"","stream_id":"stream 1"}}} /// Response:
/// {"id":5,"jsonrpc":"2.0","result":{"group":{"clients":[{"config":{"instance":2,"latency":10,"name":"Laptop","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488026485,"usec":644997},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":74}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488026481,"usec":223747},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":true,"name":"","stream_id":"stream
/// 1"}}}
result["group"] = group->toJson(); result["group"] = group->toJson();
} }
else if (request->method() == "Group.SetMute") else if (request->method() == "Group.SetMute")
@ -265,9 +281,11 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
} }
else if (request->method() == "Group.SetStream") else if (request->method() == "Group.SetStream")
{ {
/// Request: {"id":4,"jsonrpc":"2.0","method":"Group.SetStream","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","stream_id":"stream 1"}} /// Request: {"id":4,"jsonrpc":"2.0","method":"Group.SetStream","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","stream_id":"stream
/// 1"}}
/// Response: {"id":4,"jsonrpc":"2.0","result":{"stream_id":"stream 1"}} /// Response: {"id":4,"jsonrpc":"2.0","result":{"stream_id":"stream 1"}}
/// Notification: {"jsonrpc":"2.0","method":"Group.OnStreamChanged","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","stream_id":"stream 1"}} /// Notification: {"jsonrpc":"2.0","method":"Group.OnStreamChanged","params":{"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","stream_id":"stream
/// 1"}}
string streamId = request->params().get<std::string>("stream_id"); string streamId = request->params().get<std::string>("stream_id");
PcmStreamPtr stream = streamManager_->getStream(streamId); PcmStreamPtr stream = streamManager_->getStream(streamId);
if (stream == nullptr) if (stream == nullptr)
@ -293,9 +311,33 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
} }
else if (request->method() == "Group.SetClients") else if (request->method() == "Group.SetClients")
{ {
/// Request: {"id":3,"jsonrpc":"2.0","method":"Group.SetClients","params":{"clients":["00:21:6a:7d:74:fc#2","00:21:6a:7d:74:fc"],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1"}} /// Request:
/// Response: {"id":3,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025901,"usec":864472},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025905,"usec":45238},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} /// {"id":3,"jsonrpc":"2.0","method":"Group.SetClients","params":{"clients":["00:21:6a:7d:74:fc#2","00:21:6a:7d:74:fc"],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1"}}
/// Notification: {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025901,"usec":864472},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025905,"usec":45238},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} /// Response: {"id":3,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123
/// 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025901,"usec":864472},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025905,"usec":45238},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream
/// 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3
/// Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream
/// 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream
/// 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}}
/// Notification:
/// {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123
/// 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025901,"usec":864472},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025905,"usec":45238},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream
/// 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3
/// Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream
/// 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream
/// 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}}
vector<string> clients = request->params().get("clients"); vector<string> clients = request->params().get("clients");
/// Remove clients from group /// Remove clients from group
for (auto iter = group->clients.begin(); iter != group->clients.end();) for (auto iter = group->clients.begin(); iter != group->clients.end();)
@ -368,14 +410,44 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
else if (request->method() == "Server.GetStatus") else if (request->method() == "Server.GetStatus")
{ {
/// Request: {"id":1,"jsonrpc":"2.0","method":"Server.GetStatus"} /// Request: {"id":1,"jsonrpc":"2.0","method":"Server.GetStatus"}
/// Response: {"id":1,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025696,"usec":578142},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":81}},"connected":true,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025696,"usec":611255},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} /// Response: {"id":1,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123
/// 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025696,"usec":578142},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":81}},"connected":true,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025696,"usec":611255},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream
/// 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3
/// Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream
/// 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream
/// 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}}
result["server"] = Config::instance().getServerStatus(streamManager_->toJson()); result["server"] = Config::instance().getServerStatus(streamManager_->toJson());
} }
else if (request->method() == "Server.DeleteClient") else if (request->method() == "Server.DeleteClient")
{ {
/// Request: {"id":2,"jsonrpc":"2.0","method":"Server.DeleteClient","params":{"id":"00:21:6a:7d:74:fc"}} /// Request: {"id":2,"jsonrpc":"2.0","method":"Server.DeleteClient","params":{"id":"00:21:6a:7d:74:fc"}}
/// Response: {"id":2,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025751,"usec":654777},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} /// Response: {"id":2,"jsonrpc":"2.0","result":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123
/// Notification: {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025751,"usec":654777},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} /// 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025751,"usec":654777},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream
/// 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3
/// Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream
/// 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream
/// 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}}
/// Notification:
/// {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123
/// 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025751,"usec":654777},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream
/// 2"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3
/// Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream
/// 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream
/// 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}}
ClientInfoPtr clientInfo = Config::instance().getClientInfo(request->params().get<std::string>("id")); ClientInfoPtr clientInfo = Config::instance().getClientInfo(request->params().get<std::string>("id"));
if (clientInfo == nullptr) if (clientInfo == nullptr)
throw jsonrpcpp::InternalErrorException("Client not found", request->id()); throw jsonrpcpp::InternalErrorException("Client not found", request->id());
@ -505,14 +577,17 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
void StreamServer::onMessageReceived(StreamSession* streamSession, const msg::BaseMessage& baseMessage, char* buffer) void StreamServer::onMessageReceived(StreamSession* streamSession, const msg::BaseMessage& baseMessage, char* buffer)
{ {
// LOG(DEBUG) << "onMessageReceived: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " << baseMessage.refersTo << ", sent: " << baseMessage.sent.sec << "," << baseMessage.sent.usec << ", recv: " << baseMessage.received.sec << "," << baseMessage.received.usec << "\n"; // LOG(DEBUG) << "onMessageReceived: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " <<
//baseMessage.refersTo << ", sent: " << baseMessage.sent.sec << "," << baseMessage.sent.usec << ", recv: " << baseMessage.received.sec << "," <<
//baseMessage.received.usec << "\n";
if (baseMessage.type == message_type::kTime) if (baseMessage.type == message_type::kTime)
{ {
auto timeMsg = make_shared<msg::Time>(); auto timeMsg = make_shared<msg::Time>();
timeMsg->deserialize(baseMessage, buffer); timeMsg->deserialize(baseMessage, buffer);
timeMsg->refersTo = timeMsg->id; timeMsg->refersTo = timeMsg->id;
timeMsg->latency = timeMsg->received - timeMsg->sent; timeMsg->latency = timeMsg->received - timeMsg->sent;
// LOG(INFO) << "Latency sec: " << timeMsg.latency.sec << ", usec: " << timeMsg.latency.usec << ", refers to: " << timeMsg.refersTo << "\n"; // LOG(INFO) << "Latency sec: " << timeMsg.latency.sec << ", usec: " << timeMsg.latency.usec << ", refers to: " << timeMsg.refersTo <<
//"\n";
streamSession->sendAsync(timeMsg); streamSession->sendAsync(timeMsg);
// refresh streamSession state // refresh streamSession state
@ -583,7 +658,20 @@ void StreamServer::onMessageReceived(StreamSession* streamSession, const msg::Ba
if (newGroup) if (newGroup)
{ {
/// Notification: {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025796,"usec":714671},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream 2"},{"clients":[{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025798,"usec":728305},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"c5da8f7a-f377-1e51-8266-c5cc61099b71","muted":false,"name":"","stream_id":"stream 1"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3 Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}} /// Notification:
/// {"jsonrpc":"2.0","method":"Server.OnUpdate","params":{"server":{"groups":[{"clients":[{"config":{"instance":2,"latency":6,"name":"123
/// 456","volume":{"muted":false,"percent":48}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc#2","lastSeen":{"sec":1488025796,"usec":714671},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"4dcc4e3b-c699-a04b-7f0c-8260d23c43e1","muted":false,"name":"","stream_id":"stream
/// 2"},{"clients":[{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":100}},"connected":true,"host":{"arch":"x86_64","ip":"127.0.0.1","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025798,"usec":728305},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}}],"id":"c5da8f7a-f377-1e51-8266-c5cc61099b71","muted":false,"name":"","stream_id":"stream
/// 1"}],"server":{"host":{"arch":"x86_64","ip":"","mac":"","name":"T400","os":"Linux Mint 17.3
/// Rosa"},"snapserver":{"controlProtocolVersion":1,"name":"Snapserver","protocolVersion":1,"version":"0.10.0"}},"streams":[{"id":"stream
/// 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}},{"id":"stream
/// 2","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream
/// 2","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 2","scheme":"pipe"}}]}}}
json server = Config::instance().getServerStatus(streamManager_->toJson()); json server = Config::instance().getServerStatus(streamManager_->toJson());
json notification = jsonrpcpp::Notification("Server.OnUpdate", jsonrpcpp::Parameter("server", server)).to_json(); json notification = jsonrpcpp::Notification("Server.OnUpdate", jsonrpcpp::Parameter("server", server)).to_json();
controlServer_->send(notification.dump()); controlServer_->send(notification.dump());
@ -591,7 +679,10 @@ void StreamServer::onMessageReceived(StreamSession* streamSession, const msg::Ba
} }
else else
{ {
/// Notification: {"jsonrpc":"2.0","method":"Client.OnConnect","params":{"client":{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":81}},"connected":true,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux Mint 17.3 Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025524,"usec":876332},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},"id":"00:21:6a:7d:74:fc"}} /// Notification:
/// {"jsonrpc":"2.0","method":"Client.OnConnect","params":{"client":{"config":{"instance":1,"latency":0,"name":"","volume":{"muted":false,"percent":81}},"connected":true,"host":{"arch":"x86_64","ip":"192.168.0.54","mac":"00:21:6a:7d:74:fc","name":"T400","os":"Linux
/// Mint 17.3
/// Rosa"},"id":"00:21:6a:7d:74:fc","lastSeen":{"sec":1488025524,"usec":876332},"snapclient":{"name":"Snapclient","protocolVersion":2,"version":"0.10.0"}},"id":"00:21:6a:7d:74:fc"}}
json notification = jsonrpcpp::Notification("Client.OnConnect", jsonrpcpp::Parameter("id", client->id, "client", client->toJson())).to_json(); json notification = jsonrpcpp::Notification("Client.OnConnect", jsonrpcpp::Parameter("id", client->id, "client", client->toJson())).to_json();
controlServer_->send(notification.dump()); controlServer_->send(notification.dump());
////cout << "Notification: " << notification.dump() << "\n"; ////cout << "Notification: " << notification.dump() << "\n";
@ -769,4 +860,3 @@ void StreamServer::stop()
acceptor_v6_ = nullptr; acceptor_v6_ = nullptr;
} }
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -20,22 +20,22 @@
#define STREAM_SERVER_H #define STREAM_SERVER_H
#include <asio.hpp> #include <asio.hpp>
#include <vector>
#include <thread>
#include <memory> #include <memory>
#include <mutex>
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <mutex> #include <thread>
#include <vector>
#include "jsonrpcpp.hpp"
#include "streamSession.h"
#include "streamreader/streamManager.h"
#include "common/queue.h" #include "common/queue.h"
#include "common/sampleFormat.h" #include "common/sampleFormat.h"
#include "message/message.h"
#include "message/codecHeader.h"
#include "message/serverSettings.h"
#include "controlServer.h" #include "controlServer.h"
#include "jsonrpcpp.hpp"
#include "message/codecHeader.h"
#include "message/message.h"
#include "message/serverSettings.h"
#include "streamSession.h"
#include "streamreader/streamManager.h"
using asio::ip::tcp; using asio::ip::tcp;
@ -44,14 +44,8 @@ typedef std::shared_ptr<StreamSession> session_ptr;
struct StreamServerSettings struct StreamServerSettings
{ {
StreamServerSettings() : StreamServerSettings()
port(1704), : port(1704), controlPort(1705), codec("flac"), bufferMs(1000), sampleFormat("48000:16:2"), streamReadMs(20), sendAudioToMutedClients(false)
controlPort(1705),
codec("flac"),
bufferMs(1000),
sampleFormat("48000:16:2"),
streamReadMs(20),
sendAudioToMutedClients(false)
{ {
} }
size_t port; size_t port;
@ -118,5 +112,3 @@ private:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,17 +18,17 @@
#include "streamSession.h" #include "streamSession.h"
#include <iostream>
#include <mutex>
#include "aixlog.hpp" #include "aixlog.hpp"
#include "message/pcmChunk.h" #include "message/pcmChunk.h"
#include <iostream>
#include <mutex>
using namespace std; using namespace std;
StreamSession::StreamSession(MessageReceiver* receiver, std::shared_ptr<tcp::socket> socket) : StreamSession::StreamSession(MessageReceiver* receiver, std::shared_ptr<tcp::socket> socket)
active_(false), readerThread_(nullptr), writerThread_(nullptr), messageReceiver_(receiver), pcmStream_(nullptr) : active_(false), readerThread_(nullptr), writerThread_(nullptr), messageReceiver_(receiver), pcmStream_(nullptr)
{ {
socket_ = socket; socket_ = socket;
} }
@ -80,9 +80,11 @@ void StreamSession::stop()
{ {
std::lock_guard<std::mutex> socketLock(socketMutex_); std::lock_guard<std::mutex> socketLock(socketMutex_);
socket_->shutdown(asio::ip::tcp::socket::shutdown_both, ec); socket_->shutdown(asio::ip::tcp::socket::shutdown_both, ec);
if (ec) LOG(ERROR) << "Error in socket shutdown: " << ec.message() << "\n"; if (ec)
LOG(ERROR) << "Error in socket shutdown: " << ec.message() << "\n";
socket_->close(ec); socket_->close(ec);
if (ec) LOG(ERROR) << "Error in socket close: " << ec.message() << "\n"; if (ec)
LOG(ERROR) << "Error in socket close: " << ec.message() << "\n";
} }
if (readerThread_ && readerThread_->joinable()) if (readerThread_ && readerThread_->joinable())
{ {
@ -113,8 +115,7 @@ void StreamSession::socketRead(void* _to, size_t _bytes)
do do
{ {
read += socket_->read_some(asio::buffer((char*)_to + read, _bytes - read)); read += socket_->read_some(asio::buffer((char*)_to + read, _bytes - read));
} } while (active_ && (read < _bytes));
while (active_ && (read < _bytes));
} }
@ -188,7 +189,8 @@ void StreamSession::getNextMessage()
throw std::runtime_error(ss.str().c_str()); throw std::runtime_error(ss.str().c_str());
} }
// LOG(INFO) << "getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " << baseMessage.refersTo << "\n"; // LOG(INFO) << "getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " <<
//baseMessage.refersTo << "\n";
if (baseMessage.size > buffer.size()) if (baseMessage.size > buffer.size())
buffer.resize(baseMessage.size); buffer.resize(baseMessage.size);
// { // {
@ -259,5 +261,3 @@ void StreamSession::writer()
if (active_ && (messageReceiver_ != NULL)) if (active_ && (messageReceiver_ != NULL))
messageReceiver_->onDisconnect(this); messageReceiver_->onDisconnect(this);
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,17 +19,17 @@
#ifndef STREAM_SESSION_H #ifndef STREAM_SESSION_H
#define STREAM_SESSION_H #define STREAM_SESSION_H
#include "common/queue.h"
#include "message/message.h"
#include "streamreader/streamManager.h"
#include <asio.hpp>
#include <atomic>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <set>
#include <string> #include <string>
#include <thread> #include <thread>
#include <atomic>
#include <memory>
#include <asio.hpp>
#include <condition_variable>
#include <set>
#include <mutex>
#include "message/message.h"
#include "common/queue.h"
#include "streamreader/streamManager.h"
using asio::ip::tcp; using asio::ip::tcp;
@ -104,9 +104,4 @@ protected:
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,11 +17,11 @@
***/ ***/
#include "airplayStream.h" #include "airplayStream.h"
#include "common/snapException.h"
#include "common/utils/string_utils.h"
#include "common/utils.h"
#include "base64.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "base64.h"
#include "common/snapException.h"
#include "common/utils.h"
#include "common/utils/string_utils.h"
using namespace std; using namespace std;
@ -106,11 +106,15 @@ void AirplayStream::push()
if (entry_->type == "ssnc" && entry_->code == "mdst") if (entry_->type == "ssnc" && entry_->code == "mdst")
jtag_ = json(); jtag_ = json();
if(entry_->code == "asal") jtag_["ALBUM"] = data; if (entry_->code == "asal")
if(entry_->code == "asar") jtag_["ARTIST"] = data; jtag_["ALBUM"] = data;
if(entry_->code == "minm") jtag_["TITLE"] = data; if (entry_->code == "asar")
jtag_["ARTIST"] = data;
if (entry_->code == "minm")
jtag_["TITLE"] = data;
if(entry_->type == "ssnc" && entry_->code == "mden"){ if (entry_->type == "ssnc" && entry_->code == "mden")
{
// LOG(INFO) << "metadata=" << jtag_.dump(4) << "\n"; // LOG(INFO) << "metadata=" << jtag_.dump(4) << "\n";
setMeta(jtag_); setMeta(jtag_);
} }
@ -127,10 +131,12 @@ void AirplayStream::pipeReader()
{ {
ifstream pipe(pipePath_); ifstream pipe(pipePath_);
if(pipe){ if (pipe)
{
string line; string line;
while(getline(pipe, line)){ while (getline(pipe, line))
{
#ifdef HAS_EXPAT #ifdef HAS_EXPAT
parse(line); parse(line);
#endif #endif
@ -187,9 +193,11 @@ void XMLCALL AirplayStream::element_start(void *userdata, const char *element_na
string name(element_name); string name(element_name);
self->buf_.assign(""); self->buf_.assign("");
if(name == "item") self->entry_.reset(new TageEntry); if (name == "item")
self->entry_.reset(new TageEntry);
for(int i = 0; attr[i]; i += 2){ for (int i = 0; attr[i]; i += 2)
{
string name(attr[i]); string name(attr[i]);
string value(attr[i + 1]); string value(attr[i + 1]);
if (name == "encoding") if (name == "encoding")
@ -217,8 +225,10 @@ void XMLCALL AirplayStream::element_end(void *userdata, const char *element_name
else if (name == "item") else if (name == "item")
self->push(); self->push();
else if(name == "metatags") ; else if (name == "metatags")
else cout << "Unknown tag <" << name << ">\n"; ;
else
cout << "Unknown tag <" << name << ">\n";
} }
void XMLCALL AirplayStream::data(void* userdata, const char* content, int length) void XMLCALL AirplayStream::data(void* userdata, const char* content, int length)
@ -228,4 +238,3 @@ void XMLCALL AirplayStream::data(void *userdata, const char *content, int length
self->buf_.append(value); self->buf_.append(value);
} }
#endif #endif

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -32,7 +32,9 @@
class TageEntry class TageEntry
{ {
public: public:
TageEntry(): isBase64(false), length(0) {} TageEntry() : isBase64(false), length(0)
{
}
std::string code; std::string code;
std::string type; std::string type;

View file

@ -26,26 +26,29 @@
*/ */
#include "base64.h" #include "base64.h"
static const std::string base64_chars = static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
"0123456789+/"; "0123456789+/";
static inline bool is_base64(unsigned char c) { static inline bool is_base64(unsigned char c)
{
return (isalnum(c) || (c == '+') || (c == '/')); return (isalnum(c) || (c == '+') || (c == '/'));
} }
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
{
std::string ret; std::string ret;
int i = 0; int i = 0;
int j = 0; int j = 0;
unsigned char char_array_3[3]; unsigned char char_array_3[3];
unsigned char char_array_4[4]; unsigned char char_array_4[4];
while (in_len--) { while (in_len--)
{
char_array_3[i++] = *(bytes_to_encode++); char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) { if (i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
@ -72,13 +75,12 @@ std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_
while ((i++ < 3)) while ((i++ < 3))
ret += '='; ret += '=';
} }
return ret; return ret;
} }
std::string base64_decode(std::string const& encoded_string) { std::string base64_decode(std::string const& encoded_string)
{
int in_len = encoded_string.size(); int in_len = encoded_string.size();
int i = 0; int i = 0;
int j = 0; int j = 0;
@ -86,9 +88,12 @@ std::string base64_decode(std::string const& encoded_string) {
unsigned char char_array_4[4], char_array_3[3]; unsigned char char_array_4[4], char_array_3[3];
std::string ret; std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
char_array_4[i++] = encoded_string[in_]; in_++; {
if (i ==4) { char_array_4[i++] = encoded_string[in_];
in_++;
if (i == 4)
{
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_4[i] = base64_chars.find(char_array_4[i]);
@ -102,7 +107,8 @@ std::string base64_decode(std::string const& encoded_string) {
} }
} }
if (i) { if (i)
{
for (j = i; j < 4; j++) for (j = i; j < 4; j++)
char_array_4[j] = 0; char_array_4[j] = 0;
@ -113,9 +119,9 @@ std::string base64_decode(std::string const& encoded_string) {
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; for (j = 0; (j < i - 1); j++)
ret += char_array_3[j];
} }
return ret; return ret;
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,21 +16,20 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <fcntl.h>
#include <memory> #include <memory>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h>
#include "fileStream.h"
#include "encoder/encoderFactory.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/snapException.h" #include "common/snapException.h"
#include "encoder/encoderFactory.h"
#include "fileStream.h"
using namespace std; using namespace std;
FileStream::FileStream(PcmListener* pcmListener, const StreamUri& uri) : PcmStream(pcmListener, uri) FileStream::FileStream(PcmListener* pcmListener, const StreamUri& uri) : PcmStream(pcmListener, uri)
{ {
ifs.open(uri_.path.c_str(), std::ifstream::in | std::ifstream::binary); ifs.open(uri_.path.c_str(), std::ifstream::in | std::ifstream::binary);
@ -84,7 +83,8 @@ void FileStream::worker()
ifs.read(chunk->payload + count, toRead - count); ifs.read(chunk->payload + count, toRead - count);
encoder_->encode(chunk.get()); encoder_->encode(chunk.get());
if (!active_) break; if (!active_)
break;
nextTick += pcmReadMs_; nextTick += pcmReadMs_;
chronos::addUs(tvChunk, pcmReadMs_ * 1000); chronos::addUs(tvChunk, pcmReadMs_ * 1000);
long currentTick = chronos::getTickCount(); long currentTick = chronos::getTickCount();

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,23 +16,22 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <fcntl.h>
#include <memory> #include <memory>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h>
#include "encoder/encoderFactory.h" #include "aixlog.hpp"
#include "common/snapException.h" #include "common/snapException.h"
#include "common/strCompat.h" #include "common/strCompat.h"
#include "encoder/encoderFactory.h"
#include "pcmStream.h" #include "pcmStream.h"
#include "aixlog.hpp"
using namespace std; using namespace std;
PcmStream::PcmStream(PcmListener* pcmListener, const StreamUri& uri) : PcmStream::PcmStream(PcmListener* pcmListener, const StreamUri& uri) : active_(false), pcmListener_(pcmListener), uri_(uri), pcmReadMs_(20), state_(kIdle)
active_(false), pcmListener_(pcmListener), uri_(uri), pcmReadMs_(20), state_(kIdle)
{ {
EncoderFactory encoderFactory; EncoderFactory encoderFactory;
if (uri_.query.find("codec") == uri_.query.end()) if (uri_.query.find("codec") == uri_.query.end())
@ -170,9 +169,7 @@ json PcmStream::toJson() const
state = "disabled"; state = "disabled";
json j = { json j = {
{"uri", uri_.toJson()}, {"uri", uri_.toJson()}, {"id", getId()}, {"status", state},
{"id", getId()},
{"status", state},
}; };
if (meta_) if (meta_)
@ -196,4 +193,3 @@ void PcmStream::setMeta(json jtag)
if (pcmListener_) if (pcmListener_)
pcmListener_->onMetaChanged(this); pcmListener_->onMetaChanged(this);
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -19,18 +19,18 @@
#ifndef PCM_STREAM_H #ifndef PCM_STREAM_H
#define PCM_STREAM_H #define PCM_STREAM_H
#include <thread>
#include <atomic>
#include <string>
#include <mutex>
#include <condition_variable>
#include <map>
#include "streamUri.h"
#include "encoder/encoder.h"
#include "common/sampleFormat.h"
#include "common/json.hpp" #include "common/json.hpp"
#include "common/sampleFormat.h"
#include "encoder/encoder.h"
#include "message/codecHeader.h" #include "message/codecHeader.h"
#include "message/streamTags.h" #include "message/streamTags.h"
#include "streamUri.h"
#include <atomic>
#include <condition_variable>
#include <map>
#include <mutex>
#include <string>
#include <thread>
class PcmStream; class PcmStream;

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,24 +16,23 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <cerrno>
#include <fcntl.h>
#include <memory> #include <memory>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <cerrno>
#include "pipeStream.h" #include "aixlog.hpp"
#include "encoder/encoderFactory.h"
#include "common/snapException.h" #include "common/snapException.h"
#include "common/strCompat.h" #include "common/strCompat.h"
#include "aixlog.hpp" #include "encoder/encoderFactory.h"
#include "pipeStream.h"
using namespace std; using namespace std;
PipeStream::PipeStream(PcmListener* pcmListener, const StreamUri& uri) : PcmStream(pcmListener, uri), fd_(-1) PipeStream::PipeStream(PcmListener* pcmListener, const StreamUri& uri) : PcmStream(pcmListener, uri), fd_(-1)
{ {
umask(0); umask(0);
@ -108,15 +107,16 @@ void PipeStream::worker()
len += count; len += count;
idleBytes = 0; idleBytes = 0;
} }
} } while ((len < toRead) && active_);
while ((len < toRead) && active_);
if (!active_) break; if (!active_)
break;
/// TODO: use less raw pointers, make this encoding more transparent /// TODO: use less raw pointers, make this encoding more transparent
encoder_->encode(chunk.get()); encoder_->encode(chunk.get());
if (!active_) break; if (!active_)
break;
nextTick += pcmReadMs_; nextTick += pcmReadMs_;
chronos::addUs(tvChunk, pcmReadMs_ * 1000); chronos::addUs(tvChunk, pcmReadMs_ * 1000);

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,21 +17,20 @@
***/ ***/
#include <sys/stat.h>
#include <limits.h>
#include <fcntl.h>
#include "processStream.h" #include "processStream.h"
#include "common/snapException.h"
#include "common/utils/string_utils.h"
#include "common/utils.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/snapException.h"
#include "common/utils.h"
#include "common/utils/string_utils.h"
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
using namespace std; using namespace std;
ProcessStream::ProcessStream(PcmListener* pcmListener, const StreamUri& uri) : PcmStream(pcmListener, uri), path_(""), process_(nullptr) ProcessStream::ProcessStream(PcmListener* pcmListener, const StreamUri& uri) : PcmStream(pcmListener, uri), path_(""), process_(nullptr)
{ {
params_ = uri_.getQuery("params"); params_ = uri_.getQuery("params");
@ -191,14 +190,15 @@ void ProcessStream::worker()
len += count; len += count;
idleBytes = 0; idleBytes = 0;
} }
} } while ((len < toRead) && active_);
while ((len < toRead) && active_);
if (!active_) break; if (!active_)
break;
encoder_->encode(chunk.get()); encoder_->encode(chunk.get());
if (!active_) break; if (!active_)
break;
nextTick += pcmReadMs_; nextTick += pcmReadMs_;
chronos::addUs(tvChunk, pcmReadMs_ * 1000); chronos::addUs(tvChunk, pcmReadMs_ * 1000);

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,19 +16,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <regex>
#include "spotifyStream.h" #include "spotifyStream.h"
#include "common/snapException.h"
#include "common/utils/string_utils.h"
#include "common/utils.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/snapException.h"
#include "common/utils.h"
#include "common/utils/string_utils.h"
#include <regex>
using namespace std; using namespace std;
SpotifyStream::SpotifyStream(PcmListener* pcmListener, const StreamUri& uri) : ProcessStream(pcmListener, uri) SpotifyStream::SpotifyStream(PcmListener* pcmListener, const StreamUri& uri) : ProcessStream(pcmListener, uri)
{ {
sampleFormat_ = SampleFormat("44100:16:2"); sampleFormat_ = SampleFormat("44100:16:2");
@ -119,9 +118,7 @@ void SpotifyStream::onStderrMsg(const char* buffer, size_t n)
watchdog_->trigger(); watchdog_->trigger();
string logmsg = utils::string::trim_copy(string(buffer, n)); string logmsg = utils::string::trim_copy(string(buffer, n));
if ((logmsg.find("allocated stream") == string::npos) && if ((logmsg.find("allocated stream") == string::npos) && (logmsg.find("Got channel") == string::npos) && (logmsg.find('\0') == string::npos) &&
(logmsg.find("Got channel") == string::npos) &&
(logmsg.find('\0') == string::npos) &&
(logmsg.size() > 4)) (logmsg.size() > 4))
{ {
LOG(INFO) << "(" << getName() << ") " << logmsg << "\n"; LOG(INFO) << "(" << getName() << ") " << logmsg << "\n";
@ -141,9 +138,7 @@ void SpotifyStream::onStderrMsg(const char* buffer, size_t n)
{ {
LOG(INFO) << "metadata: <" << m[1] << ">\n"; LOG(INFO) << "metadata: <" << m[1] << ">\n";
json jtag = { json jtag = {{"TITLE", (string)m[1]}};
{"TITLE", (string)m[1]}
};
setMeta(jtag); setMeta(jtag);
} }
} }
@ -175,5 +170,3 @@ void SpotifyStream::onTimeout(const Watchdog* watchdog, size_t ms)
if (process_) if (process_)
process_->kill(); process_->kill();
} }

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -28,7 +28,8 @@
* Implements EncoderListener to get the encoded data. * Implements EncoderListener to get the encoded data.
* Data is passed to the PcmListener * Data is passed to the PcmListener
* usage: * usage:
* snapserver -s "spotify:///librespot?name=Spotify&username=<my username>&password=<my password>[&devicename=Snapcast][&bitrate=320][&volume=<volume in percent>][&cache=<cache dir>]" * snapserver -s "spotify:///librespot?name=Spotify&username=<my username>&password=<my password>[&devicename=Snapcast][&bitrate=320][&volume=<volume in
* percent>][&cache=<cache dir>]"
*/ */
class SpotifyStream : public ProcessStream, WatchdogListener class SpotifyStream : public ProcessStream, WatchdogListener
{ {

View file

@ -1,6 +1,6 @@
/*** /***
This file is part of snapcast This file is part of snapcast
Copyright (C) 2014-2018 Johannes Pohl Copyright (C) 2014-2019 Johannes Pohl
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,20 +18,21 @@
#include "streamManager.h" #include "streamManager.h"
#include "airplayStream.h" #include "airplayStream.h"
#include "spotifyStream.h"
#include "processStream.h"
#include "pipeStream.h"
#include "fileStream.h"
#include "common/utils.h"
#include "common/strCompat.h"
#include "aixlog.hpp" #include "aixlog.hpp"
#include "common/snapException.h" #include "common/snapException.h"
#include "common/strCompat.h"
#include "common/utils.h"
#include "fileStream.h"
#include "pipeStream.h"
#include "processStream.h"
#include "spotifyStream.h"
using namespace std; using namespace std;
StreamManager::StreamManager(PcmListener* pcmListener, const std::string& defaultSampleFormat, const std::string& defaultCodec, size_t defaultReadBufferMs) : pcmListener_(pcmListener), sampleFormat_(defaultSampleFormat), codec_(defaultCodec), readBufferMs_(defaultReadBufferMs) StreamManager::StreamManager(PcmListener* pcmListener, const std::string& defaultSampleFormat, const std::string& defaultCodec, size_t defaultReadBufferMs)
: pcmListener_(pcmListener), sampleFormat_(defaultSampleFormat), codec_(defaultCodec), readBufferMs_(defaultReadBufferMs)
{ {
} }
@ -142,5 +143,3 @@ json StreamManager::toJson() const
result.push_back(stream->toJson()); result.push_back(stream->toJson());
return result; return result;
} }

View file

@ -1,10 +1,10 @@
#ifndef PCM_READER_FACTORY_H #ifndef PCM_READER_FACTORY_H
#define PCM_READER_FACTORY_H #define PCM_READER_FACTORY_H
#include "pcmStream.h"
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <memory>
#include "pcmStream.h"
typedef std::shared_ptr<PcmStream> PcmStreamPtr; typedef std::shared_ptr<PcmStream> PcmStreamPtr;

Some files were not shown because too many files have changed in this diff Show more