mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-10 07:36:41 +02:00
Tidy up
This commit is contained in:
parent
1aa8831416
commit
f5d4fcaf43
34 changed files with 274 additions and 273 deletions
|
@ -1,30 +1,29 @@
|
||||||
/***
|
/***
|
||||||
This file is part of avahi.
|
This file is part of snapcast
|
||||||
|
Copyright (C) 2014-2021 Johannes Pohl
|
||||||
|
|
||||||
avahi is free software; you can redistribute it and/or modify it
|
This program is free software: you can redistribute it and/or modify
|
||||||
under the terms of the GNU Lesser General Public License as
|
it under the terms of the GNU General Public License as published by
|
||||||
published by the Free Software Foundation; either version 2.1 of the
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
License, or (at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
avahi is distributed in the hope that it will be useful, but WITHOUT
|
This program is distributed in the hope that it will be useful,
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU General Public License
|
||||||
License along with avahi; if not, write to the Free Software
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
||||||
USA.
|
|
||||||
***/
|
***/
|
||||||
|
|
||||||
#include "browse_avahi.hpp"
|
#include "browse_avahi.hpp"
|
||||||
#include "common/aixlog.hpp"
|
#include "common/aixlog.hpp"
|
||||||
#include "common/snap_exception.hpp"
|
#include "common/snap_exception.hpp"
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
|
||||||
static AvahiSimplePoll* simple_poll = nullptr;
|
static AvahiSimplePoll* simple_poll = nullptr;
|
||||||
|
@ -45,15 +44,15 @@ BrowseAvahi::~BrowseAvahi()
|
||||||
|
|
||||||
void BrowseAvahi::cleanUp()
|
void BrowseAvahi::cleanUp()
|
||||||
{
|
{
|
||||||
if (sb_)
|
if (sb_ != nullptr)
|
||||||
avahi_service_browser_free(sb_);
|
avahi_service_browser_free(sb_);
|
||||||
sb_ = nullptr;
|
sb_ = nullptr;
|
||||||
|
|
||||||
if (client_)
|
if (client_ != nullptr)
|
||||||
avahi_client_free(client_);
|
avahi_client_free(client_);
|
||||||
client_ = nullptr;
|
client_ = nullptr;
|
||||||
|
|
||||||
if (simple_poll)
|
if (simple_poll != nullptr)
|
||||||
avahi_simple_poll_free(simple_poll);
|
avahi_simple_poll_free(simple_poll);
|
||||||
simple_poll = nullptr;
|
simple_poll = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +63,7 @@ void BrowseAvahi::resolve_callback(AvahiServiceResolver* r, AVAHI_GCC_UNUSED Ava
|
||||||
const AvahiAddress* address, uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags flags,
|
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);
|
auto* browseAvahi = static_cast<BrowseAvahi*>(userdata);
|
||||||
assert(r);
|
assert(r);
|
||||||
|
|
||||||
/* Called whenever a service has been resolved successfully or timed out */
|
/* Called whenever a service has been resolved successfully or timed out */
|
||||||
|
@ -87,20 +86,20 @@ void BrowseAvahi::resolve_callback(AvahiServiceResolver* r, AVAHI_GCC_UNUSED Ava
|
||||||
browseAvahi->result_.ip = a;
|
browseAvahi->result_.ip = a;
|
||||||
browseAvahi->result_.port = port;
|
browseAvahi->result_.port = port;
|
||||||
// protocol seems to be unreliable (0 for IPv4 and for IPv6)
|
// protocol seems to be unreliable (0 for IPv4 and for IPv6)
|
||||||
browseAvahi->result_.ip_version = (browseAvahi->result_.ip.find(":") == std::string::npos) ? (IPVersion::IPv4) : (IPVersion::IPv6);
|
browseAvahi->result_.ip_version = (browseAvahi->result_.ip.find(':') == std::string::npos) ? (IPVersion::IPv4) : (IPVersion::IPv6);
|
||||||
browseAvahi->result_.valid = true;
|
browseAvahi->result_.valid = true;
|
||||||
browseAvahi->result_.iface_idx = interface;
|
browseAvahi->result_.iface_idx = interface;
|
||||||
|
|
||||||
t = avahi_string_list_to_string(txt);
|
t = avahi_string_list_to_string(txt);
|
||||||
LOG(INFO, LOG_TAG) << "\t" << host_name << ":" << port << " (" << a << ")\n";
|
LOG(INFO, LOG_TAG) << "\t" << host_name << ":" << port << " (" << a << ")\n";
|
||||||
LOG(DEBUG, LOG_TAG) << "\tTXT=" << t << "\n";
|
LOG(DEBUG, LOG_TAG) << "\tTXT=" << t << "\n";
|
||||||
LOG(DEBUG, LOG_TAG) << "\tProto=" << (int)protocol << "\n";
|
LOG(DEBUG, LOG_TAG) << "\tProto=" << static_cast<int>(protocol) << "\n";
|
||||||
LOG(DEBUG, LOG_TAG) << "\tcookie is " << avahi_string_list_get_service_cookie(txt) << "\n";
|
LOG(DEBUG, LOG_TAG) << "\tcookie is " << avahi_string_list_get_service_cookie(txt) << "\n";
|
||||||
LOG(DEBUG, LOG_TAG) << "\tis_local: " << !!(flags & AVAHI_LOOKUP_RESULT_LOCAL) << "\n";
|
LOG(DEBUG, LOG_TAG) << "\tis_local: " << !((flags & AVAHI_LOOKUP_RESULT_LOCAL) == 0) << "\n";
|
||||||
LOG(DEBUG, LOG_TAG) << "\tour_own: " << !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN) << "\n";
|
LOG(DEBUG, LOG_TAG) << "\tour_own: " << !((flags & AVAHI_LOOKUP_RESULT_OUR_OWN) == 0) << "\n";
|
||||||
LOG(DEBUG, LOG_TAG) << "\twide_area: " << !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA) << "\n";
|
LOG(DEBUG, LOG_TAG) << "\twide_area: " << !((flags & AVAHI_LOOKUP_RESULT_WIDE_AREA) == 0) << "\n";
|
||||||
LOG(DEBUG, LOG_TAG) << "\tmulticast: " << !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST) << "\n";
|
LOG(DEBUG, LOG_TAG) << "\tmulticast: " << !((flags & AVAHI_LOOKUP_RESULT_MULTICAST) == 0) << "\n";
|
||||||
LOG(DEBUG, LOG_TAG) << "\tcached: " << !!(flags & AVAHI_LOOKUP_RESULT_CACHED) << "\n";
|
LOG(DEBUG, LOG_TAG) << "\tcached: " << !((flags & AVAHI_LOOKUP_RESULT_CACHED) == 0) << "\n";
|
||||||
avahi_free(t);
|
avahi_free(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +113,7 @@ void BrowseAvahi::browse_callback(AvahiServiceBrowser* b, AvahiIfIndex interface
|
||||||
{
|
{
|
||||||
|
|
||||||
// AvahiClient* client = (AvahiClient*)userdata;
|
// AvahiClient* client = (AvahiClient*)userdata;
|
||||||
BrowseAvahi* browseAvahi = static_cast<BrowseAvahi*>(userdata);
|
auto* browseAvahi = static_cast<BrowseAvahi*>(userdata);
|
||||||
assert(b);
|
assert(b);
|
||||||
|
|
||||||
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
|
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
|
||||||
|
@ -134,8 +133,8 @@ void BrowseAvahi::browse_callback(AvahiServiceBrowser* b, AvahiIfIndex interface
|
||||||
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,
|
if ((avahi_service_resolver_new(browseAvahi->client_, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(0),
|
||||||
resolve_callback, userdata)))
|
resolve_callback, userdata)) == nullptr)
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to resolve service '" << name << "': " << avahi_strerror(avahi_client_errno(browseAvahi->client_)) << "\n";
|
LOG(ERROR, LOG_TAG) << "Failed to resolve service '" << name << "': " << avahi_strerror(avahi_client_errno(browseAvahi->client_)) << "\n";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -172,17 +171,17 @@ bool BrowseAvahi::browse(const std::string& serviceName, mDNSResult& result, int
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
/* Allocate main loop object */
|
/* Allocate main loop object */
|
||||||
if (!(simple_poll = avahi_simple_poll_new()))
|
if ((simple_poll = avahi_simple_poll_new()) == nullptr)
|
||||||
throw SnapException("BrowseAvahi - Failed to create simple poll object");
|
throw SnapException("BrowseAvahi - Failed to create simple poll object");
|
||||||
|
|
||||||
/* Allocate a new client */
|
/* Allocate a new client */
|
||||||
int error;
|
int error;
|
||||||
if (!(client_ = avahi_client_new(avahi_simple_poll_get(simple_poll), (AvahiClientFlags)0, client_callback, this, &error)))
|
if ((client_ = avahi_client_new(avahi_simple_poll_get(simple_poll), static_cast<AvahiClientFlags>(0), client_callback, this, &error)) == nullptr)
|
||||||
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(), nullptr, (AvahiLookupFlags)0, browse_callback,
|
if ((sb_ = avahi_service_browser_new(client_, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, serviceName.c_str(), nullptr, static_cast<AvahiLookupFlags>(0),
|
||||||
this)))
|
browse_callback, this)) == nullptr)
|
||||||
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;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -278,8 +278,8 @@ void Controller::sendTimeSyncMessage(int quick_syncs)
|
||||||
if (quick_syncs > 0)
|
if (quick_syncs > 0)
|
||||||
{
|
{
|
||||||
if (--quick_syncs == 0)
|
if (--quick_syncs == 0)
|
||||||
LOG(INFO, LOG_TAG) << "diff to server [ms]: " << (float)TimeProvider::getInstance().getDiffToServer<chronos::usec>().count() / 1000.f
|
LOG(INFO, LOG_TAG) << "diff to server [ms]: "
|
||||||
<< "\n";
|
<< static_cast<float>(TimeProvider::getInstance().getDiffToServer<chronos::usec>().count()) / 1000.f << "\n";
|
||||||
next = 100us;
|
next = 100us;
|
||||||
}
|
}
|
||||||
timer_.expires_after(next);
|
timer_.expires_after(next);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -70,15 +70,15 @@ bool FlacDecoder::decode(msg::PcmChunk* chunk)
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
cacheInfo_.reset();
|
cacheInfo_.reset();
|
||||||
pcmChunk = chunk;
|
pcmChunk = chunk;
|
||||||
flacChunk->payload = (char*)realloc(flacChunk->payload, chunk->payloadSize);
|
flacChunk->payload = static_cast<char*>(realloc(flacChunk->payload, chunk->payloadSize));
|
||||||
memcpy(flacChunk->payload, chunk->payload, chunk->payloadSize);
|
memcpy(flacChunk->payload, chunk->payload, chunk->payloadSize);
|
||||||
flacChunk->payloadSize = chunk->payloadSize;
|
flacChunk->payloadSize = chunk->payloadSize;
|
||||||
|
|
||||||
pcmChunk->payload = (char*)realloc(pcmChunk->payload, 0);
|
pcmChunk->payload = static_cast<char*>(realloc(pcmChunk->payload, 0));
|
||||||
pcmChunk->payloadSize = 0;
|
pcmChunk->payloadSize = 0;
|
||||||
while (flacChunk->payloadSize > 0)
|
while (flacChunk->payloadSize > 0)
|
||||||
{
|
{
|
||||||
if (!FLAC__stream_decoder_process_single(decoder))
|
if (FLAC__stream_decoder_process_single(decoder) == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder* /*decoder
|
||||||
memcpy(buffer, flacChunk->payload, *bytes);
|
memcpy(buffer, flacChunk->payload, *bytes);
|
||||||
memmove(flacChunk->payload, flacChunk->payload + *bytes, flacChunk->payloadSize - *bytes);
|
memmove(flacChunk->payload, flacChunk->payload + *bytes, flacChunk->payloadSize - *bytes);
|
||||||
flacChunk->payloadSize = flacChunk->payloadSize - static_cast<uint32_t>(*bytes);
|
flacChunk->payloadSize = flacChunk->payloadSize - static_cast<uint32_t>(*bytes);
|
||||||
flacChunk->payload = (char*)realloc(flacChunk->payload, flacChunk->payloadSize);
|
flacChunk->payload = static_cast<char*>(realloc(flacChunk->payload, flacChunk->payloadSize));
|
||||||
}
|
}
|
||||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
@ -160,11 +160,11 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* /*decod
|
||||||
{
|
{
|
||||||
size_t bytes = frame->header.blocksize * sampleFormat.frameSize();
|
size_t bytes = frame->header.blocksize * sampleFormat.frameSize();
|
||||||
|
|
||||||
FlacDecoder* flacDecoder = static_cast<FlacDecoder*>(client_data);
|
auto* flacDecoder = static_cast<FlacDecoder*>(client_data);
|
||||||
if (flacDecoder->cacheInfo_.isCachedChunk_)
|
if (flacDecoder->cacheInfo_.isCachedChunk_)
|
||||||
flacDecoder->cacheInfo_.cachedBlocks_ += frame->header.blocksize;
|
flacDecoder->cacheInfo_.cachedBlocks_ += frame->header.blocksize;
|
||||||
|
|
||||||
pcmChunk->payload = (char*)realloc(pcmChunk->payload, pcmChunk->payloadSize + bytes);
|
pcmChunk->payload = static_cast<char*>(realloc(pcmChunk->payload, pcmChunk->payloadSize + bytes));
|
||||||
|
|
||||||
for (size_t channel = 0; channel < sampleFormat.channels(); ++channel)
|
for (size_t channel = 0; channel < sampleFormat.channels(); ++channel)
|
||||||
{
|
{
|
||||||
|
@ -176,19 +176,19 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* /*decod
|
||||||
|
|
||||||
if (sampleFormat.sampleSize() == 1)
|
if (sampleFormat.sampleSize() == 1)
|
||||||
{
|
{
|
||||||
int8_t* chunkBuffer = (int8_t*)(pcmChunk->payload + pcmChunk->payloadSize);
|
auto* chunkBuffer = reinterpret_cast<int8_t*>(pcmChunk->payload + pcmChunk->payloadSize);
|
||||||
for (size_t i = 0; i < frame->header.blocksize; i++)
|
for (size_t i = 0; i < frame->header.blocksize; i++)
|
||||||
chunkBuffer[sampleFormat.channels() * i + channel] = (int8_t)(buffer[channel][i]);
|
chunkBuffer[sampleFormat.channels() * i + channel] = static_cast<int8_t>(buffer[channel][i]);
|
||||||
}
|
}
|
||||||
else if (sampleFormat.sampleSize() == 2)
|
else if (sampleFormat.sampleSize() == 2)
|
||||||
{
|
{
|
||||||
int16_t* chunkBuffer = (int16_t*)(pcmChunk->payload + pcmChunk->payloadSize);
|
auto* chunkBuffer = reinterpret_cast<int16_t*>(pcmChunk->payload + pcmChunk->payloadSize);
|
||||||
for (size_t i = 0; i < frame->header.blocksize; i++)
|
for (size_t i = 0; i < frame->header.blocksize; i++)
|
||||||
chunkBuffer[sampleFormat.channels() * i + channel] = SWAP_16((int16_t)(buffer[channel][i]));
|
chunkBuffer[sampleFormat.channels() * i + channel] = SWAP_16((int16_t)(buffer[channel][i]));
|
||||||
}
|
}
|
||||||
else if (sampleFormat.sampleSize() == 4)
|
else if (sampleFormat.sampleSize() == 4)
|
||||||
{
|
{
|
||||||
int32_t* chunkBuffer = (int32_t*)(pcmChunk->payload + pcmChunk->payloadSize);
|
auto* chunkBuffer = reinterpret_cast<int32_t*>(pcmChunk->payload + pcmChunk->payloadSize);
|
||||||
for (size_t i = 0; i < frame->header.blocksize; i++)
|
for (size_t i = 0; i < frame->header.blocksize; i++)
|
||||||
chunkBuffer[sampleFormat.channels() * i + channel] = SWAP_32((int32_t)(buffer[channel][i]));
|
chunkBuffer[sampleFormat.channels() * i + channel] = SWAP_32((int32_t)(buffer[channel][i]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -81,7 +81,7 @@ bool OggDecoder::decode(msg::PcmChunk* chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
ogg_stream_pagein(&os, &og); /* can safely ignore errors at this point */
|
ogg_stream_pagein(&os, &og); /* can safely ignore errors at this point */
|
||||||
while (1)
|
while (true)
|
||||||
{
|
{
|
||||||
result = ogg_stream_packetout(&os, &op);
|
result = ogg_stream_packetout(&os, &op);
|
||||||
|
|
||||||
|
@ -108,12 +108,12 @@ bool OggDecoder::decode(msg::PcmChunk* chunk)
|
||||||
while ((samples = vorbis_synthesis_pcmout(&vd, &pcm)) > 0)
|
while ((samples = vorbis_synthesis_pcmout(&vd, &pcm)) > 0)
|
||||||
{
|
{
|
||||||
uint32_t bytes = sampleFormat_.sampleSize() * vi.channels * samples;
|
uint32_t bytes = sampleFormat_.sampleSize() * vi.channels * samples;
|
||||||
chunk->payload = (char*)realloc(chunk->payload, chunk->payloadSize + bytes);
|
chunk->payload = static_cast<char*>(realloc(chunk->payload, chunk->payloadSize + bytes));
|
||||||
for (int channel = 0; channel < vi.channels; ++channel)
|
for (int channel = 0; channel < vi.channels; ++channel)
|
||||||
{
|
{
|
||||||
if (sampleFormat_.sampleSize() == 1)
|
if (sampleFormat_.sampleSize() == 1)
|
||||||
{
|
{
|
||||||
int8_t* chunkBuffer = (int8_t*)(chunk->payload + chunk->payloadSize);
|
auto* chunkBuffer = reinterpret_cast<int8_t*>(chunk->payload + chunk->payloadSize);
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
{
|
{
|
||||||
int8_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
|
int8_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
|
||||||
|
@ -126,7 +126,7 @@ bool OggDecoder::decode(msg::PcmChunk* chunk)
|
||||||
}
|
}
|
||||||
else if (sampleFormat_.sampleSize() == 2)
|
else if (sampleFormat_.sampleSize() == 2)
|
||||||
{
|
{
|
||||||
int16_t* chunkBuffer = (int16_t*)(chunk->payload + chunk->payloadSize);
|
auto* chunkBuffer = reinterpret_cast<int16_t*>(chunk->payload + chunk->payloadSize);
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
{
|
{
|
||||||
int16_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
|
int16_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
|
||||||
|
@ -139,7 +139,7 @@ bool OggDecoder::decode(msg::PcmChunk* chunk)
|
||||||
}
|
}
|
||||||
else if (sampleFormat_.sampleSize() == 4)
|
else if (sampleFormat_.sampleSize() == 4)
|
||||||
{
|
{
|
||||||
int32_t* chunkBuffer = (int32_t*)(chunk->payload + chunk->payloadSize);
|
auto* chunkBuffer = reinterpret_cast<int32_t*>(chunk->payload + chunk->payloadSize);
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
{
|
{
|
||||||
int32_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
|
int32_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
|
||||||
|
@ -229,11 +229,11 @@ SampleFormat OggDecoder::setHeader(msg::CodecHeader* chunk)
|
||||||
|
|
||||||
/* Throw the comments plus a few lines about the bitstream we're decoding */
|
/* Throw the comments plus a few lines about the bitstream we're decoding */
|
||||||
char** ptr = vc.user_comments;
|
char** ptr = vc.user_comments;
|
||||||
while (*ptr)
|
while (*ptr != nullptr)
|
||||||
{
|
{
|
||||||
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, LOG_TAG) << "comment: " << comment << "\n";
|
LOG(INFO, LOG_TAG) << "comment: " << comment << "\n";
|
||||||
;
|
;
|
||||||
++ptr;
|
++ptr;
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2015 Hannes Ellinger
|
Copyright (C) 2015 Hannes Ellinger
|
||||||
|
Copyright (C) 2016-2021 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
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
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 "opus_decoder.hpp"
|
#include "opus_decoder.hpp"
|
||||||
|
@ -51,7 +52,7 @@ bool OpusDecoder::decode(msg::PcmChunk* chunk)
|
||||||
{
|
{
|
||||||
int decoded_frames = 0;
|
int decoded_frames = 0;
|
||||||
|
|
||||||
while ((decoded_frames = opus_decode(dec_, (unsigned char*)chunk->payload, chunk->payloadSize, pcm_.data(),
|
while ((decoded_frames = opus_decode(dec_, reinterpret_cast<unsigned char*>(chunk->payload), chunk->payloadSize, pcm_.data(),
|
||||||
static_cast<int>(pcm_.size()) / sample_format_.channels(), 0)) == OPUS_BUFFER_TOO_SMALL)
|
static_cast<int>(pcm_.size()) / sample_format_.channels(), 0)) == OPUS_BUFFER_TOO_SMALL)
|
||||||
{
|
{
|
||||||
if (pcm_.size() < const_max_frame_size * sample_format_.channels())
|
if (pcm_.size() < const_max_frame_size * sample_format_.channels())
|
||||||
|
@ -76,8 +77,8 @@ bool OpusDecoder::decode(msg::PcmChunk* chunk)
|
||||||
|
|
||||||
// copy encoded data to chunk
|
// copy encoded data to chunk
|
||||||
chunk->payloadSize = decoded_frames * sample_format_.frameSize(); // decoded_frames * sample_format_.channels() * sizeof(opus_int16);
|
chunk->payloadSize = decoded_frames * sample_format_.frameSize(); // decoded_frames * sample_format_.channels() * sizeof(opus_int16);
|
||||||
chunk->payload = (char*)realloc(chunk->payload, chunk->payloadSize);
|
chunk->payload = static_cast<char*>(realloc(chunk->payload, chunk->payloadSize));
|
||||||
memcpy(chunk->payload, (char*)pcm_.data(), chunk->payloadSize);
|
memcpy(chunk->payload, reinterpret_cast<char*>(pcm_.data()), chunk->payloadSize);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -195,7 +195,7 @@ void AlsaPlayer::waitForEvent()
|
||||||
|
|
||||||
unsigned short revents;
|
unsigned short revents;
|
||||||
snd_ctl_poll_descriptors_revents(ctl_, fd_.get(), 1, &revents);
|
snd_ctl_poll_descriptors_revents(ctl_, fd_.get(), 1, &revents);
|
||||||
if (revents & POLLIN || (revents == 0))
|
if (((revents & POLLIN) != 0) || (revents == 0))
|
||||||
{
|
{
|
||||||
snd_ctl_event_t* event;
|
snd_ctl_event_t* event;
|
||||||
snd_ctl_event_alloca(&event);
|
snd_ctl_event_alloca(&event);
|
||||||
|
@ -266,7 +266,7 @@ void AlsaPlayer::initMixer()
|
||||||
if ((err = snd_mixer_load(mixer_)) < 0)
|
if ((err = snd_mixer_load(mixer_)) < 0)
|
||||||
throw SnapException(std::string("Failed to load mixer, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to load mixer, error: ") + snd_strerror(err));
|
||||||
elem_ = snd_mixer_find_selem(mixer_, sid);
|
elem_ = snd_mixer_find_selem(mixer_, sid);
|
||||||
if (!elem_)
|
if (elem_ == nullptr)
|
||||||
throw SnapException("Failed to find mixer: " + mixer_name_);
|
throw SnapException("Failed to find mixer: " + mixer_name_);
|
||||||
|
|
||||||
sd_ = boost::asio::posix::stream_descriptor(io_context_, fd_->fd);
|
sd_ = boost::asio::posix::stream_descriptor(io_context_, fd_->fd);
|
||||||
|
@ -345,9 +345,9 @@ void AlsaPlayer::initAlsa()
|
||||||
{
|
{
|
||||||
stringstream ss;
|
stringstream ss;
|
||||||
ss << "Can't set format: " << string(snd_strerror(err)) << ", supported: ";
|
ss << "Can't set format: " << string(snd_strerror(err)) << ", supported: ";
|
||||||
for (int format = 0; format <= (int)SND_PCM_FORMAT_LAST; format++)
|
for (int format = 0; format <= static_cast<int>(SND_PCM_FORMAT_LAST); format++)
|
||||||
{
|
{
|
||||||
snd_pcm_format_t snd_pcm_format = static_cast<snd_pcm_format_t>(format);
|
auto snd_pcm_format = static_cast<snd_pcm_format_t>(format);
|
||||||
if (snd_pcm_hw_params_test_format(handle_, params, snd_pcm_format) == 0)
|
if (snd_pcm_hw_params_test_format(handle_, params, snd_pcm_format) == 0)
|
||||||
ss << snd_pcm_format_name(snd_pcm_format) << " ";
|
ss << snd_pcm_format_name(snd_pcm_format) << " ";
|
||||||
}
|
}
|
||||||
|
@ -416,7 +416,7 @@ void AlsaPlayer::initAlsa()
|
||||||
// Resume information
|
// Resume information
|
||||||
// uint32_t periods;
|
// uint32_t periods;
|
||||||
if (snd_pcm_hw_params_get_periods(params, &periods, nullptr) < 0)
|
if (snd_pcm_hw_params_get_periods(params, &periods, nullptr) < 0)
|
||||||
periods = round((double)buffer_time / (double)period_time);
|
periods = round(static_cast<double>(buffer_time) / static_cast<double>(period_time));
|
||||||
snd_pcm_hw_params_get_period_size(params, &frames_, nullptr);
|
snd_pcm_hw_params_get_period_size(params, &frames_, nullptr);
|
||||||
LOG(INFO, LOG_TAG) << "PCM name: " << snd_pcm_name(handle_) << ", sample rate: " << rate << " Hz, channels: " << channels
|
LOG(INFO, LOG_TAG) << "PCM name: " << snd_pcm_name(handle_) << ", sample rate: " << rate << " Hz, channels: " << channels
|
||||||
<< ", buffer time: " << buffer_time << " us, periods: " << periods << ", period time: " << period_time
|
<< ", buffer time: " << buffer_time << " us, periods: " << periods << ", period time: " << period_time
|
||||||
|
@ -617,7 +617,7 @@ void AlsaPlayer::worker()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LOG(TRACE, LOG_TAG) << "res: " << result << ", framesAvail: " << framesAvail << ", delay: " << framesDelay << ", frames: " << frames_ << "\n";
|
// LOG(TRACE, LOG_TAG) << "res: " << result << ", framesAvail: " << framesAvail << ", delay: " << framesDelay << ", frames: " << frames_ << "\n";
|
||||||
chronos::usec delay(static_cast<chronos::usec::rep>(1000 * (double)framesDelay / format.msRate()));
|
chronos::usec delay(static_cast<chronos::usec::rep>(1000 * static_cast<double>(framesDelay) / format.msRate()));
|
||||||
// LOG(TRACE, LOG_TAG) << "delay: " << framesDelay << ", delay[ms]: " << delay.count() / 1000 << ", avail: " << framesAvail << "\n";
|
// LOG(TRACE, LOG_TAG) << "delay: " << framesDelay << ", delay[ms]: " << delay.count() / 1000 << ", avail: " << framesAvail << "\n";
|
||||||
|
|
||||||
if (buffer_.size() < static_cast<size_t>(framesAvail * format.frameSize()))
|
if (buffer_.size() < static_cast<size_t>(framesAvail * format.frameSize()))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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,7 +16,7 @@
|
||||||
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 <assert.h>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "common/aixlog.hpp"
|
#include "common/aixlog.hpp"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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,7 +16,7 @@
|
||||||
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 <assert.h>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "common/aixlog.hpp"
|
#include "common/aixlog.hpp"
|
||||||
|
@ -96,7 +96,7 @@ vector<PcmDevice> PulsePlayer::pcm_list(const std::string& parameter)
|
||||||
throw SnapException("PulseAudio context failed, error: " + std::string(pa_strerror(pa_context_errno(pa_ctx.get()))));
|
throw SnapException("PulseAudio context failed, error: " + std::string(pa_strerror(pa_context_errno(pa_ctx.get()))));
|
||||||
|
|
||||||
static std::vector<PcmDevice> devices;
|
static std::vector<PcmDevice> devices;
|
||||||
auto op = pa_context_get_sink_info_list(
|
auto* op = pa_context_get_sink_info_list(
|
||||||
pa_ctx.get(),
|
pa_ctx.get(),
|
||||||
[](pa_context* ctx, const pa_sink_info* i, int eol, void* userdata) mutable {
|
[](pa_context* ctx, const pa_sink_info* i, int eol, void* userdata) mutable {
|
||||||
std::ignore = ctx;
|
std::ignore = ctx;
|
||||||
|
@ -194,10 +194,10 @@ void PulsePlayer::triggerVolumeUpdate()
|
||||||
[](pa_context* ctx, const pa_sink_input_info* info, int eol, void* userdata) {
|
[](pa_context* ctx, const pa_sink_input_info* info, int eol, void* userdata) {
|
||||||
std::ignore = ctx;
|
std::ignore = ctx;
|
||||||
LOG(DEBUG, LOG_TAG) << "pa_context_get_sink_info_by_index info: " << (info != nullptr) << ", eol: " << eol << "\n";
|
LOG(DEBUG, LOG_TAG) << "pa_context_get_sink_info_by_index info: " << (info != nullptr) << ", eol: " << eol << "\n";
|
||||||
if (info)
|
if (info != nullptr)
|
||||||
{
|
{
|
||||||
auto self = static_cast<PulsePlayer*>(userdata);
|
auto* self = static_cast<PulsePlayer*>(userdata);
|
||||||
self->volume_ = (double)pa_cvolume_avg(&(info->volume)) / (double)PA_VOLUME_NORM;
|
self->volume_ = static_cast<double>(pa_cvolume_avg(&(info->volume))) / static_cast<double>(PA_VOLUME_NORM);
|
||||||
self->muted_ = (info->mute != 0);
|
self->muted_ = (info->mute != 0);
|
||||||
LOG(DEBUG, LOG_TAG) << "Volume changed: " << self->volume_ << ", muted: " << self->muted_ << "\n";
|
LOG(DEBUG, LOG_TAG) << "Volume changed: " << self->volume_ << ", muted: " << self->muted_ << "\n";
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ void PulsePlayer::subscribeCallback(pa_context* ctx, pa_subscription_event_type_
|
||||||
if (facility == PA_SUBSCRIPTION_EVENT_SINK_INPUT)
|
if (facility == PA_SUBSCRIPTION_EVENT_SINK_INPUT)
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "event_type: " << event_type << ", facility: " << facility << "\n";
|
LOG(DEBUG, LOG_TAG) << "event_type: " << event_type << ", facility: " << facility << "\n";
|
||||||
if (playstream_ && (idx == pa_stream_get_index(playstream_)))
|
if ((playstream_ != nullptr) && (idx == pa_stream_get_index(playstream_)))
|
||||||
triggerVolumeUpdate();
|
triggerVolumeUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,7 +351,7 @@ void PulsePlayer::start()
|
||||||
pa_context_set_state_callback(
|
pa_context_set_state_callback(
|
||||||
pa_ctx_,
|
pa_ctx_,
|
||||||
[](pa_context* c, void* userdata) {
|
[](pa_context* c, void* userdata) {
|
||||||
auto self = static_cast<PulsePlayer*>(userdata);
|
auto* self = static_cast<PulsePlayer*>(userdata);
|
||||||
self->stateCallback(c);
|
self->stateCallback(c);
|
||||||
},
|
},
|
||||||
this);
|
this);
|
||||||
|
@ -373,7 +373,7 @@ void PulsePlayer::start()
|
||||||
throw SnapException("PulseAudio is not ready, error: " + std::string(pa_strerror(pa_context_errno(pa_ctx_))));
|
throw SnapException("PulseAudio is not ready, error: " + std::string(pa_strerror(pa_context_errno(pa_ctx_))));
|
||||||
|
|
||||||
playstream_ = pa_stream_new(pa_ctx_, "Playback", &pa_ss_, nullptr);
|
playstream_ = pa_stream_new(pa_ctx_, "Playback", &pa_ss_, nullptr);
|
||||||
if (!playstream_)
|
if (playstream_ == nullptr)
|
||||||
throw SnapException("Failed to create PulseAudio stream");
|
throw SnapException("Failed to create PulseAudio stream");
|
||||||
|
|
||||||
if (settings_.mixer.mode == ClientSettings::Mixer::Mode::hardware)
|
if (settings_.mixer.mode == ClientSettings::Mixer::Mode::hardware)
|
||||||
|
@ -381,19 +381,19 @@ void PulsePlayer::start()
|
||||||
pa_context_set_subscribe_callback(
|
pa_context_set_subscribe_callback(
|
||||||
pa_ctx_,
|
pa_ctx_,
|
||||||
[](pa_context* ctx, pa_subscription_event_type_t event_type, uint32_t idx, void* userdata) {
|
[](pa_context* ctx, pa_subscription_event_type_t event_type, uint32_t idx, void* userdata) {
|
||||||
auto self = static_cast<PulsePlayer*>(userdata);
|
auto* self = static_cast<PulsePlayer*>(userdata);
|
||||||
self->subscribeCallback(ctx, event_type, idx);
|
self->subscribeCallback(ctx, event_type, idx);
|
||||||
},
|
},
|
||||||
this);
|
this);
|
||||||
const pa_subscription_mask_t mask = static_cast<pa_subscription_mask_t>(PA_SUBSCRIPTION_MASK_SINK_INPUT);
|
const auto mask = static_cast<pa_subscription_mask_t>(PA_SUBSCRIPTION_MASK_SINK_INPUT);
|
||||||
|
|
||||||
pa_context_subscribe(
|
pa_context_subscribe(
|
||||||
pa_ctx_, mask,
|
pa_ctx_, mask,
|
||||||
[](pa_context* ctx, int success, void* userdata) {
|
[](pa_context* ctx, int success, void* userdata) {
|
||||||
std::ignore = ctx;
|
std::ignore = ctx;
|
||||||
if (success)
|
if (success != 0)
|
||||||
{
|
{
|
||||||
auto self = static_cast<PulsePlayer*>(userdata);
|
auto* self = static_cast<PulsePlayer*>(userdata);
|
||||||
self->triggerVolumeUpdate();
|
self->triggerVolumeUpdate();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -403,7 +403,7 @@ void PulsePlayer::start()
|
||||||
pa_stream_set_write_callback(
|
pa_stream_set_write_callback(
|
||||||
playstream_,
|
playstream_,
|
||||||
[](pa_stream* stream, size_t length, void* userdata) {
|
[](pa_stream* stream, size_t length, void* userdata) {
|
||||||
auto self = static_cast<PulsePlayer*>(userdata);
|
auto* self = static_cast<PulsePlayer*>(userdata);
|
||||||
self->writeCallback(stream, length);
|
self->writeCallback(stream, length);
|
||||||
},
|
},
|
||||||
this);
|
this);
|
||||||
|
@ -411,7 +411,7 @@ void PulsePlayer::start()
|
||||||
pa_stream_set_underflow_callback(
|
pa_stream_set_underflow_callback(
|
||||||
playstream_,
|
playstream_,
|
||||||
[](pa_stream* stream, void* userdata) {
|
[](pa_stream* stream, void* userdata) {
|
||||||
auto self = static_cast<PulsePlayer*>(userdata);
|
auto* self = static_cast<PulsePlayer*>(userdata);
|
||||||
self->underflowCallback(stream);
|
self->underflowCallback(stream);
|
||||||
},
|
},
|
||||||
this);
|
this);
|
||||||
|
@ -445,27 +445,27 @@ void PulsePlayer::start()
|
||||||
void PulsePlayer::stop()
|
void PulsePlayer::stop()
|
||||||
{
|
{
|
||||||
LOG(INFO, LOG_TAG) << "Stop\n";
|
LOG(INFO, LOG_TAG) << "Stop\n";
|
||||||
if (pa_ml_)
|
if (pa_ml_ != nullptr)
|
||||||
{
|
{
|
||||||
pa_mainloop_quit(pa_ml_, 0);
|
pa_mainloop_quit(pa_ml_, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::stop();
|
Player::stop();
|
||||||
|
|
||||||
if (pa_ctx_)
|
if (pa_ctx_ != nullptr)
|
||||||
{
|
{
|
||||||
pa_context_disconnect(pa_ctx_);
|
pa_context_disconnect(pa_ctx_);
|
||||||
pa_context_unref(pa_ctx_);
|
pa_context_unref(pa_ctx_);
|
||||||
pa_ctx_ = nullptr;
|
pa_ctx_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pa_ml_)
|
if (pa_ml_ != nullptr)
|
||||||
{
|
{
|
||||||
pa_mainloop_free(pa_ml_);
|
pa_mainloop_free(pa_ml_);
|
||||||
pa_ml_ = nullptr;
|
pa_ml_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playstream_)
|
if (playstream_ != nullptr)
|
||||||
{
|
{
|
||||||
pa_stream_set_state_callback(playstream_, nullptr, nullptr);
|
pa_stream_set_state_callback(playstream_, nullptr, nullptr);
|
||||||
pa_stream_set_read_callback(playstream_, nullptr, nullptr);
|
pa_stream_set_read_callback(playstream_, nullptr, nullptr);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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,7 +19,7 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#ifndef WINDOWS
|
#ifndef WINDOWS
|
||||||
#include <signal.h>
|
#include <csignal>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ int main(int argc, char** argv)
|
||||||
string logformat = "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)";
|
string logformat = "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)";
|
||||||
if (settings.logging.sink.find("file:") != string::npos)
|
if (settings.logging.sink.find("file:") != string::npos)
|
||||||
{
|
{
|
||||||
string logfile = settings.logging.sink.substr(settings.logging.sink.find(":") + 1);
|
string logfile = settings.logging.sink.substr(settings.logging.sink.find(':') + 1);
|
||||||
AixLog::Log::init<AixLog::SinkFile>(logfilter, logfile, logformat);
|
AixLog::Log::init<AixLog::SinkFile>(logfilter, logfile, logformat);
|
||||||
}
|
}
|
||||||
else if (settings.logging.sink == "stdout")
|
else if (settings.logging.sink == "stdout")
|
||||||
|
@ -315,7 +315,7 @@ int main(int argc, char** argv)
|
||||||
if (userValue->is_set())
|
if (userValue->is_set())
|
||||||
{
|
{
|
||||||
if (userValue->value().empty())
|
if (userValue->value().empty())
|
||||||
std::invalid_argument("user must not be empty");
|
throw std::invalid_argument("user must not be empty");
|
||||||
|
|
||||||
vector<string> user_group = utils::string::split(userValue->value(), ':');
|
vector<string> user_group = utils::string::split(userValue->value(), ':');
|
||||||
user = user_group[0];
|
user = user_group[0];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -27,8 +27,8 @@
|
||||||
#include "common/utils/logging.hpp"
|
#include "common/utils/logging.hpp"
|
||||||
#include "time_provider.hpp"
|
#include "time_provider.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -334,7 +334,7 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
|
||||||
<< ", age: " << std::chrono::duration_cast<cs::usec>(age).count() / 1000. << "\n";
|
<< ", age: " << std::chrono::duration_cast<cs::usec>(age).count() / 1000. << "\n";
|
||||||
getSilentPlayerChunk(outputBuffer, silent_frames);
|
getSilentPlayerChunk(outputBuffer, silent_frames);
|
||||||
}
|
}
|
||||||
getNextPlayerChunk((char*)outputBuffer + (chunk_->format.frameSize() * silent_frames), frames - silent_frames);
|
getNextPlayerChunk(static_cast<char*>(outputBuffer) + (chunk_->format.frameSize() * silent_frames), frames - silent_frames);
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
@ -353,7 +353,7 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
|
||||||
if (correctAfterXFrames_ != 0)
|
if (correctAfterXFrames_ != 0)
|
||||||
{
|
{
|
||||||
playedFrames_ += frames;
|
playedFrames_ += frames;
|
||||||
if (playedFrames_ >= (uint32_t)abs(correctAfterXFrames_))
|
if (playedFrames_ >= static_cast<uint32_t>(abs(correctAfterXFrames_)))
|
||||||
{
|
{
|
||||||
framesCorrection = static_cast<int32_t>(playedFrames_) / correctAfterXFrames_;
|
framesCorrection = static_cast<int32_t>(playedFrames_) / correctAfterXFrames_;
|
||||||
playedFrames_ %= abs(correctAfterXFrames_);
|
playedFrames_ %= abs(correctAfterXFrames_);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -33,7 +33,8 @@ void TimeProvider::setDiff(const tv& c2s, const tv& s2c)
|
||||||
{
|
{
|
||||||
// tv latency = c2s - s2c;
|
// tv latency = c2s - s2c;
|
||||||
// double diff = (latency.sec * 1000. + latency.usec / 1000.) / 2.;
|
// double diff = (latency.sec * 1000. + latency.usec / 1000.) / 2.;
|
||||||
double diff = ((double)c2s.sec / 2. - (double)s2c.sec / 2.) * 1000. + ((double)c2s.usec / 2. - (double)s2c.usec / 2.) / 1000.;
|
double diff = (static_cast<double>(c2s.sec) / 2. - static_cast<double>(s2c.sec) / 2.) * 1000. +
|
||||||
|
(static_cast<double>(c2s.usec) / 2. - static_cast<double>(s2c.usec) / 2.) / 1000.;
|
||||||
setDiffToServer(diff);
|
setDiffToServer(diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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,12 +22,12 @@
|
||||||
#include "common/str_compat.hpp"
|
#include "common/str_compat.hpp"
|
||||||
#include "common/utils.hpp"
|
#include "common/utils.hpp"
|
||||||
#include "common/utils/file_utils.hpp"
|
#include "common/utils/file_utils.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
@ -62,8 +62,8 @@ void Daemon::daemonize()
|
||||||
throw SnapException("Could not open PID lock file \"" + pidfile_ + "\"");
|
throw SnapException("Could not open PID lock file \"" + pidfile_ + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
uid_t user_uid = (uid_t)-1;
|
auto user_uid = static_cast<uid_t>(-1);
|
||||||
gid_t user_gid = (gid_t)-1;
|
auto user_gid = static_cast<gid_t>(-1);
|
||||||
std::string user_name;
|
std::string user_name;
|
||||||
// #ifdef FREEBSD
|
// #ifdef FREEBSD
|
||||||
// bool had_group = false;
|
// bool had_group = false;
|
||||||
|
@ -78,7 +78,7 @@ void Daemon::daemonize()
|
||||||
user_gid = pwd->pw_gid;
|
user_gid = pwd->pw_gid;
|
||||||
user_name = strdup(user_.c_str());
|
user_name = strdup(user_.c_str());
|
||||||
/// this is needed by libs such as arts
|
/// this is needed by libs such as arts
|
||||||
setenv("HOME", pwd->pw_dir, true);
|
setenv("HOME", pwd->pw_dir, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!group_.empty())
|
if (!group_.empty())
|
||||||
|
@ -99,8 +99,8 @@ void Daemon::daemonize()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// set gid
|
/// set gid
|
||||||
if (user_gid != (gid_t)-1 && user_gid != getgid() && setgid(user_gid) == -1)
|
if (user_gid != static_cast<gid_t>(-1) && user_gid != getgid() && setgid(user_gid) == -1)
|
||||||
throw SnapException("Failed to set group " + cpt::to_string((int)user_gid));
|
throw SnapException("Failed to set group " + cpt::to_string(static_cast<int>(user_gid)));
|
||||||
|
|
||||||
//#if defined(FREEBSD) && !defined(MACOS)
|
//#if defined(FREEBSD) && !defined(MACOS)
|
||||||
//#ifdef FREEBSD
|
//#ifdef FREEBSD
|
||||||
|
@ -111,7 +111,7 @@ void Daemon::daemonize()
|
||||||
// throw SnapException("Failed to set supplementary groups of user \"" + user + "\"");
|
// throw SnapException("Failed to set supplementary groups of user \"" + user + "\"");
|
||||||
//#endif
|
//#endif
|
||||||
/// set uid
|
/// set uid
|
||||||
if (user_uid != (uid_t)-1 && user_uid != getuid() && setuid(user_uid) == -1)
|
if (user_uid != static_cast<uid_t>(-1) && user_uid != getuid() && setuid(user_uid) == -1)
|
||||||
throw SnapException("Failed to set user " + user_);
|
throw SnapException("Failed to set user " + user_);
|
||||||
|
|
||||||
/// Our process ID and Session ID
|
/// Our process ID and Session ID
|
||||||
|
@ -155,7 +155,7 @@ void Daemon::daemonize()
|
||||||
sprintf(str, "%d\n", getpid());
|
sprintf(str, "%d\n", getpid());
|
||||||
|
|
||||||
/// write pid to lockfile
|
/// write pid to lockfile
|
||||||
if (write(pidFilehandle_, str, strlen(str)) != (int)strlen(str))
|
if (write(pidFilehandle_, str, strlen(str)) != static_cast<int>(strlen(str)))
|
||||||
throw SnapException("Could not write PID to lock file \"" + pidfile_ + "\"");
|
throw SnapException("Could not write PID to lock file \"" + pidfile_ + "\"");
|
||||||
|
|
||||||
/// Close out the standard file descriptors
|
/// Close out the standard file descriptors
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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,8 +16,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
***/
|
***/
|
||||||
|
|
||||||
#ifndef MESSAGE_H
|
#ifndef MESSAGE_HPP
|
||||||
#define MESSAGE_H
|
#define MESSAGE_HPP
|
||||||
|
|
||||||
#include "common/endian.hpp"
|
#include "common/endian.hpp"
|
||||||
#include "common/time_defs.hpp"
|
#include "common/time_defs.hpp"
|
||||||
|
@ -232,7 +232,7 @@ protected:
|
||||||
|
|
||||||
void writeVal(std::ostream& stream, const std::string& val) const
|
void writeVal(std::ostream& stream, const std::string& val) const
|
||||||
{
|
{
|
||||||
uint32_t size = static_cast<uint32_t>(val.size());
|
auto size = static_cast<uint32_t>(val.size());
|
||||||
writeVal(stream, val.c_str(), size);
|
writeVal(stream, val.c_str(), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -46,7 +46,7 @@ Resampler::Resampler(const SampleFormat& in_format, const SampleFormat& out_form
|
||||||
soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, 0);
|
soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, 0);
|
||||||
soxr_ =
|
soxr_ =
|
||||||
soxr_create(static_cast<double>(in_format_.rate()), static_cast<double>(out_format_.rate()), in_format_.channels(), &error, &iospec, &q_spec, NULL);
|
soxr_create(static_cast<double>(in_format_.rate()), static_cast<double>(out_format_.rate()), in_format_.channels(), &error, &iospec, &q_spec, NULL);
|
||||||
if (error)
|
if (error != nullptr)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Error soxr_create: " << error << "\n";
|
LOG(ERROR, LOG_TAG) << "Error soxr_create: " << error << "\n";
|
||||||
soxr_ = nullptr;
|
soxr_ = nullptr;
|
||||||
|
@ -118,7 +118,7 @@ std::shared_ptr<msg::PcmChunk> Resampler::resample(const msg::PcmChunk& chunk)
|
||||||
if (in_format_.bits() == 24)
|
if (in_format_.bits() == 24)
|
||||||
{
|
{
|
||||||
// sox expects 32 bit input, shift 8 bits left
|
// sox expects 32 bit input, shift 8 bits left
|
||||||
int32_t* frames = (int32_t*)chunk.payload;
|
auto* frames = reinterpret_cast<int32_t*>(chunk.payload);
|
||||||
for (size_t n = 0; n < chunk.getSampleCount(); ++n)
|
for (size_t n = 0; n < chunk.getSampleCount(); ++n)
|
||||||
frames[n] = frames[n] << 8;
|
frames[n] = frames[n] << 8;
|
||||||
}
|
}
|
||||||
|
@ -126,8 +126,8 @@ std::shared_ptr<msg::PcmChunk> Resampler::resample(const msg::PcmChunk& chunk)
|
||||||
size_t idone;
|
size_t idone;
|
||||||
size_t odone;
|
size_t odone;
|
||||||
auto resample_buffer_framesize = resample_buffer_.size() / out_format_.frameSize();
|
auto resample_buffer_framesize = resample_buffer_.size() / out_format_.frameSize();
|
||||||
auto error = soxr_process(soxr_, chunk.payload, chunk.getFrameCount(), &idone, resample_buffer_.data(), resample_buffer_framesize, &odone);
|
const auto* error = soxr_process(soxr_, chunk.payload, chunk.getFrameCount(), &idone, resample_buffer_.data(), resample_buffer_framesize, &odone);
|
||||||
if (error)
|
if (error != nullptr)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Error soxr_process: " << error << "\n";
|
LOG(ERROR, LOG_TAG) << "Error soxr_process: " << error << "\n";
|
||||||
}
|
}
|
||||||
|
@ -151,13 +151,13 @@ std::shared_ptr<msg::PcmChunk> Resampler::resample(const msg::PcmChunk& chunk)
|
||||||
|
|
||||||
// copy from the resample_buffer to the resampled chunk
|
// copy from the resample_buffer to the resampled chunk
|
||||||
resampled_chunk->payloadSize = static_cast<uint32_t>(odone * out_format_.frameSize());
|
resampled_chunk->payloadSize = static_cast<uint32_t>(odone * out_format_.frameSize());
|
||||||
resampled_chunk->payload = (char*)realloc(resampled_chunk->payload, resampled_chunk->payloadSize);
|
resampled_chunk->payload = static_cast<char*>(realloc(resampled_chunk->payload, resampled_chunk->payloadSize));
|
||||||
memcpy(resampled_chunk->payload, resample_buffer_.data(), resampled_chunk->payloadSize);
|
memcpy(resampled_chunk->payload, resample_buffer_.data(), resampled_chunk->payloadSize);
|
||||||
|
|
||||||
if (out_format_.bits() == 24)
|
if (out_format_.bits() == 24)
|
||||||
{
|
{
|
||||||
// sox has quantized to 32 bit, shift 8 bits right
|
// sox has quantized to 32 bit, shift 8 bits right
|
||||||
int32_t* frames = (int32_t*)resampled_chunk->payload;
|
auto* frames = reinterpret_cast<int32_t*>(resampled_chunk->payload);
|
||||||
for (size_t n = 0; n < resampled_chunk->getSampleCount(); ++n)
|
for (size_t n = 0; n < resampled_chunk->getSampleCount(); ++n)
|
||||||
{
|
{
|
||||||
// +128 to round to the nearest so that quantisation steps are distributed evenly
|
// +128 to round to the nearest so that quantisation steps are distributed evenly
|
||||||
|
@ -211,7 +211,7 @@ shared_ptr<msg::PcmChunk> Resampler::resample(shared_ptr<msg::PcmChunk> chunk)
|
||||||
Resampler::~Resampler()
|
Resampler::~Resampler()
|
||||||
{
|
{
|
||||||
#ifdef HAS_SOXR
|
#ifdef HAS_SOXR
|
||||||
if (soxr_)
|
if (soxr_ != nullptr)
|
||||||
soxr_delete(soxr_);
|
soxr_delete(soxr_);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -94,7 +94,7 @@ void Config::init(const std::string& root_directory, const std::string& user, co
|
||||||
{
|
{
|
||||||
json j;
|
json j;
|
||||||
ifs >> j;
|
ifs >> j;
|
||||||
if (j.count("ConfigVersion"))
|
if (j.count("ConfigVersion") != 0u)
|
||||||
{
|
{
|
||||||
json jGroups = j["Groups"];
|
json jGroups = j["Groups"];
|
||||||
for (auto& jGroup : jGroups)
|
for (auto& jGroup : jGroups)
|
||||||
|
@ -132,7 +132,7 @@ ClientInfoPtr Config::getClientInfo(const std::string& clientId) const
|
||||||
if (clientId.empty())
|
if (clientId.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
for (auto group : groups)
|
for (const auto& group : groups)
|
||||||
{
|
{
|
||||||
for (auto client : group->clients)
|
for (auto client : group->clients)
|
||||||
{
|
{
|
||||||
|
@ -183,7 +183,7 @@ GroupPtr Config::getGroupFromClient(const std::string& clientId)
|
||||||
{
|
{
|
||||||
for (auto group : groups)
|
for (auto group : groups)
|
||||||
{
|
{
|
||||||
for (auto c : group->clients)
|
for (const auto& c : group->clients)
|
||||||
{
|
{
|
||||||
if (c->id == clientId)
|
if (c->id == clientId)
|
||||||
return group;
|
return group;
|
||||||
|
@ -219,7 +219,7 @@ json Config::getServerStatus(const json& streams) const
|
||||||
json Config::getGroups() const
|
json Config::getGroups() const
|
||||||
{
|
{
|
||||||
json result = json::array();
|
json result = json::array();
|
||||||
for (auto group : groups)
|
for (const auto& group : groups)
|
||||||
result.push_back(group->toJson());
|
result.push_back(group->toJson());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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,7 +62,7 @@ void ControlServer::cleanup()
|
||||||
void ControlServer::send(const std::string& message, const ControlSession* excludeSession)
|
void ControlServer::send(const std::string& message, const ControlSession* excludeSession)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> mlock(session_mutex_);
|
std::lock_guard<std::recursive_mutex> mlock(session_mutex_);
|
||||||
for (auto s : sessions_)
|
for (const auto& s : sessions_)
|
||||||
{
|
{
|
||||||
if (auto session = s.lock())
|
if (auto session = s.lock())
|
||||||
{
|
{
|
||||||
|
@ -199,7 +199,7 @@ void ControlServer::stop()
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> mlock(session_mutex_);
|
std::lock_guard<std::recursive_mutex> mlock(session_mutex_);
|
||||||
cleanup();
|
cleanup();
|
||||||
for (auto s : sessions_)
|
for (const auto& s : sessions_)
|
||||||
{
|
{
|
||||||
if (auto session = s.lock())
|
if (auto session = s.lock())
|
||||||
session->stop();
|
session->stop();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -42,10 +42,10 @@ std::unique_ptr<Encoder> EncoderFactory::createEncoder(const std::string& codecS
|
||||||
{
|
{
|
||||||
std::string codec(codecSettings);
|
std::string codec(codecSettings);
|
||||||
std::string codecOptions;
|
std::string codecOptions;
|
||||||
if (codec.find(":") != std::string::npos)
|
if (codec.find(':') != std::string::npos)
|
||||||
{
|
{
|
||||||
codecOptions = utils::string::trim_copy(codec.substr(codec.find(":") + 1));
|
codecOptions = utils::string::trim_copy(codec.substr(codec.find(':') + 1));
|
||||||
codec = utils::string::trim_copy(codec.substr(0, codec.find(":")));
|
codec = utils::string::trim_copy(codec.substr(0, codec.find(':')));
|
||||||
}
|
}
|
||||||
if (codec == "pcm")
|
if (codec == "pcm")
|
||||||
return std::make_unique<PcmEncoder>(codecOptions);
|
return std::make_unique<PcmEncoder>(codecOptions);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -33,7 +33,7 @@ namespace encoder
|
||||||
FlacEncoder::FlacEncoder(const std::string& codecOptions) : Encoder(codecOptions), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0), flacChunk_(nullptr)
|
FlacEncoder::FlacEncoder(const std::string& codecOptions) : Encoder(codecOptions), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0), flacChunk_(nullptr)
|
||||||
{
|
{
|
||||||
headerChunk_.reset(new msg::CodecHeader("flac"));
|
headerChunk_.reset(new msg::CodecHeader("flac"));
|
||||||
pcmBuffer_ = (FLAC__int32*)malloc(pcmBufferSize_ * sizeof(FLAC__int32));
|
pcmBuffer_ = static_cast<FLAC__int32*>(malloc(pcmBufferSize_ * sizeof(FLAC__int32)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,26 +82,26 @@ void FlacEncoder::encode(const msg::PcmChunk& chunk)
|
||||||
if (pcmBufferSize_ < samples)
|
if (pcmBufferSize_ < samples)
|
||||||
{
|
{
|
||||||
pcmBufferSize_ = samples;
|
pcmBufferSize_ = samples;
|
||||||
pcmBuffer_ = (FLAC__int32*)realloc(pcmBuffer_, pcmBufferSize_ * sizeof(FLAC__int32));
|
pcmBuffer_ = static_cast<FLAC__int32*>(realloc(pcmBuffer_, pcmBufferSize_ * sizeof(FLAC__int32)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sampleFormat_.sampleSize() == 1)
|
if (sampleFormat_.sampleSize() == 1)
|
||||||
{
|
{
|
||||||
FLAC__int8* buffer = (FLAC__int8*)chunk.payload;
|
auto* buffer = reinterpret_cast<FLAC__int8*>(chunk.payload);
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
pcmBuffer_[i] = (FLAC__int32)(buffer[i]);
|
pcmBuffer_[i] = static_cast<FLAC__int32>(buffer[i]);
|
||||||
}
|
}
|
||||||
else if (sampleFormat_.sampleSize() == 2)
|
else if (sampleFormat_.sampleSize() == 2)
|
||||||
{
|
{
|
||||||
FLAC__int16* buffer = (FLAC__int16*)chunk.payload;
|
auto* buffer = reinterpret_cast<FLAC__int16*>(chunk.payload);
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
pcmBuffer_[i] = (FLAC__int32)(buffer[i]);
|
pcmBuffer_[i] = static_cast<FLAC__int32>(buffer[i]);
|
||||||
}
|
}
|
||||||
else if (sampleFormat_.sampleSize() == 4)
|
else if (sampleFormat_.sampleSize() == 4)
|
||||||
{
|
{
|
||||||
FLAC__int32* buffer = (FLAC__int32*)chunk.payload;
|
auto* buffer = reinterpret_cast<FLAC__int32*>(chunk.payload);
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
pcmBuffer_[i] = (FLAC__int32)(buffer[i]);
|
pcmBuffer_[i] = buffer[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,13 +124,13 @@ FLAC__StreamEncoderWriteStatus FlacEncoder::write_callback(const FLAC__StreamEnc
|
||||||
// LOG(INFO, LOG_TAG) << "write_callback: " << bytes << ", " << samples << ", " << current_frame << "\n";
|
// LOG(INFO, LOG_TAG) << "write_callback: " << bytes << ", " << samples << ", " << current_frame << "\n";
|
||||||
if ((current_frame == 0) && (bytes > 0) && (samples == 0))
|
if ((current_frame == 0) && (bytes > 0) && (samples == 0))
|
||||||
{
|
{
|
||||||
headerChunk_->payload = (char*)realloc(headerChunk_->payload, headerChunk_->payloadSize + bytes);
|
headerChunk_->payload = static_cast<char*>(realloc(headerChunk_->payload, headerChunk_->payloadSize + bytes));
|
||||||
memcpy(headerChunk_->payload + headerChunk_->payloadSize, buffer, bytes);
|
memcpy(headerChunk_->payload + headerChunk_->payloadSize, buffer, bytes);
|
||||||
headerChunk_->payloadSize += bytes;
|
headerChunk_->payloadSize += bytes;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flacChunk_->payload = (char*)realloc(flacChunk_->payload, flacChunk_->payloadSize + bytes);
|
flacChunk_->payload = static_cast<char*>(realloc(flacChunk_->payload, flacChunk_->payloadSize + bytes));
|
||||||
memcpy(flacChunk_->payload + flacChunk_->payloadSize, buffer, bytes);
|
memcpy(flacChunk_->payload + flacChunk_->payloadSize, buffer, bytes);
|
||||||
flacChunk_->payloadSize += bytes;
|
flacChunk_->payloadSize += bytes;
|
||||||
encodedSamples_ += samples;
|
encodedSamples_ += samples;
|
||||||
|
@ -143,7 +143,7 @@ namespace callback
|
||||||
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples,
|
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples,
|
||||||
unsigned current_frame, void* client_data)
|
unsigned current_frame, void* client_data)
|
||||||
{
|
{
|
||||||
FlacEncoder* flacEncoder = (FlacEncoder*)client_data;
|
auto* flacEncoder = static_cast<FlacEncoder*>(client_data);
|
||||||
return flacEncoder->write_callback(encoder, buffer, bytes, samples, current_frame);
|
return flacEncoder->write_callback(encoder, buffer, bytes, samples, current_frame);
|
||||||
}
|
}
|
||||||
} // namespace callback
|
} // namespace callback
|
||||||
|
@ -164,7 +164,7 @@ void FlacEncoder::initEncoder()
|
||||||
throw SnapException("compression level has to be between 0 and 8");
|
throw SnapException("compression level has to be between 0 and 8");
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAC__bool ok = true;
|
FLAC__bool ok = 1;
|
||||||
FLAC__StreamEncoderInitStatus init_status;
|
FLAC__StreamEncoderInitStatus init_status;
|
||||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ void FlacEncoder::initEncoder()
|
||||||
if ((encoder_ = FLAC__stream_encoder_new()) == nullptr)
|
if ((encoder_ = FLAC__stream_encoder_new()) == nullptr)
|
||||||
throw SnapException("error allocating encoder");
|
throw SnapException("error allocating encoder");
|
||||||
|
|
||||||
ok &= FLAC__stream_encoder_set_verify(encoder_, true);
|
ok &= FLAC__stream_encoder_set_verify(encoder_, 1);
|
||||||
// compression levels (0-8):
|
// compression levels (0-8):
|
||||||
// https://xiph.org/flac/api/group__flac__stream__encoder.html#gae49cf32f5256cb47eecd33779493ac85
|
// https://xiph.org/flac/api/group__flac__stream__encoder.html#gae49cf32f5256cb47eecd33779493ac85
|
||||||
// latency:
|
// latency:
|
||||||
|
@ -183,22 +183,22 @@ void FlacEncoder::initEncoder()
|
||||||
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder_, sampleFormat_.bits());
|
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder_, sampleFormat_.bits());
|
||||||
ok &= FLAC__stream_encoder_set_sample_rate(encoder_, sampleFormat_.rate());
|
ok &= FLAC__stream_encoder_set_sample_rate(encoder_, sampleFormat_.rate());
|
||||||
|
|
||||||
if (!ok)
|
if (ok == 0)
|
||||||
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 ((metadata_[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == nullptr ||
|
if ((metadata_[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == nullptr ||
|
||||||
(metadata_[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == nullptr ||
|
(metadata_[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == nullptr ||
|
||||||
// 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") == 0) ||
|
||||||
!FLAC__metadata_object_vorbiscomment_append_comment(metadata_[0], entry, false) ||
|
(FLAC__metadata_object_vorbiscomment_append_comment(metadata_[0], entry, 0) == 0) ||
|
||||||
!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "VERSION", VERSION) ||
|
(FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "VERSION", VERSION) == 0) ||
|
||||||
!FLAC__metadata_object_vorbiscomment_append_comment(metadata_[0], entry, false))
|
(FLAC__metadata_object_vorbiscomment_append_comment(metadata_[0], entry, 0) == 0))
|
||||||
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
|
||||||
ok = FLAC__stream_encoder_set_metadata(encoder_, metadata_, 2);
|
ok = FLAC__stream_encoder_set_metadata(encoder_, metadata_, 2);
|
||||||
if (!ok)
|
if (ok == 0)
|
||||||
throw SnapException("error setting meta data");
|
throw SnapException("error setting meta data");
|
||||||
|
|
||||||
// initialize encoder
|
// initialize encoder
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -80,19 +80,19 @@ void OggEncoder::encode(const msg::PcmChunk& chunk)
|
||||||
{
|
{
|
||||||
if (sampleFormat_.sampleSize() == 1)
|
if (sampleFormat_.sampleSize() == 1)
|
||||||
{
|
{
|
||||||
int8_t* chunkBuffer = (int8_t*)chunk.payload;
|
auto* chunkBuffer = reinterpret_cast<int8_t*>(chunk.payload);
|
||||||
for (int i = 0; i < frames; i++)
|
for (int i = 0; i < frames; i++)
|
||||||
buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 128.f;
|
buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 128.f;
|
||||||
}
|
}
|
||||||
else if (sampleFormat_.sampleSize() == 2)
|
else if (sampleFormat_.sampleSize() == 2)
|
||||||
{
|
{
|
||||||
int16_t* chunkBuffer = (int16_t*)chunk.payload;
|
auto* chunkBuffer = reinterpret_cast<int16_t*>(chunk.payload);
|
||||||
for (int i = 0; i < frames; i++)
|
for (int i = 0; i < frames; i++)
|
||||||
buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 32768.f;
|
buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 32768.f;
|
||||||
}
|
}
|
||||||
else if (sampleFormat_.sampleSize() == 4)
|
else if (sampleFormat_.sampleSize() == 4)
|
||||||
{
|
{
|
||||||
int32_t* chunkBuffer = (int32_t*)chunk.payload;
|
auto* chunkBuffer = reinterpret_cast<int32_t*>(chunk.payload);
|
||||||
for (int i = 0; i < frames; i++)
|
for (int i = 0; i < frames; i++)
|
||||||
buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 2147483648.f;
|
buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 2147483648.f;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ void OggEncoder::encode(const msg::PcmChunk& chunk)
|
||||||
vorbis_analysis(&vb_, nullptr);
|
vorbis_analysis(&vb_, nullptr);
|
||||||
vorbis_bitrate_addblock(&vb_);
|
vorbis_bitrate_addblock(&vb_);
|
||||||
|
|
||||||
while (vorbis_bitrate_flushpacket(&vd_, &op_))
|
while (vorbis_bitrate_flushpacket(&vd_, &op_) != 0)
|
||||||
{
|
{
|
||||||
/* weld the packet into the bitstream */
|
/* weld the packet into the bitstream */
|
||||||
ogg_stream_packetin(&os_, &op_);
|
ogg_stream_packetin(&os_, &op_);
|
||||||
|
@ -129,14 +129,14 @@ void OggEncoder::encode(const msg::PcmChunk& chunk)
|
||||||
size_t nextLen = pos + og_.header_len + og_.body_len;
|
size_t nextLen = pos + og_.header_len + og_.body_len;
|
||||||
// make chunk larger
|
// make chunk larger
|
||||||
if (oggChunk->payloadSize < nextLen)
|
if (oggChunk->payloadSize < nextLen)
|
||||||
oggChunk->payload = (char*)realloc(oggChunk->payload, nextLen);
|
oggChunk->payload = static_cast<char*>(realloc(oggChunk->payload, nextLen));
|
||||||
|
|
||||||
memcpy(oggChunk->payload + pos, og_.header, og_.header_len);
|
memcpy(oggChunk->payload + pos, og_.header, og_.header_len);
|
||||||
pos += og_.header_len;
|
pos += og_.header_len;
|
||||||
memcpy(oggChunk->payload + pos, og_.body, og_.body_len);
|
memcpy(oggChunk->payload + pos, og_.body, og_.body_len);
|
||||||
pos += og_.body_len;
|
pos += og_.body_len;
|
||||||
|
|
||||||
if (ogg_page_eos(&og_))
|
if (ogg_page_eos(&og_) != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ void OggEncoder::encode(const msg::PcmChunk& chunk)
|
||||||
// LOG(INFO, LOG_TAG) << "res: " << res << "\n";
|
// LOG(INFO, LOG_TAG) << "res: " << res << "\n";
|
||||||
lastGranulepos_ = os_.granulepos;
|
lastGranulepos_ = os_.granulepos;
|
||||||
// make oggChunk smaller
|
// make oggChunk smaller
|
||||||
oggChunk->payload = (char*)realloc(oggChunk->payload, pos);
|
oggChunk->payload = static_cast<char*>(realloc(oggChunk->payload, pos));
|
||||||
oggChunk->payloadSize = pos;
|
oggChunk->payloadSize = pos;
|
||||||
encoded_callback_(*this, oggChunk, res);
|
encoded_callback_(*this, oggChunk, res);
|
||||||
}
|
}
|
||||||
|
@ -157,13 +157,13 @@ void OggEncoder::encode(const msg::PcmChunk& chunk)
|
||||||
|
|
||||||
void OggEncoder::initEncoder()
|
void OggEncoder::initEncoder()
|
||||||
{
|
{
|
||||||
if (codecOptions_.find(":") == string::npos)
|
if (codecOptions_.find(':') == string::npos)
|
||||||
throw SnapException("Invalid codec options: \"" + codecOptions_ + "\"");
|
throw SnapException("Invalid codec options: \"" + codecOptions_ + "\"");
|
||||||
string mode = utils::string::trim_copy(codecOptions_.substr(0, codecOptions_.find(":")));
|
string mode = utils::string::trim_copy(codecOptions_.substr(0, codecOptions_.find(':')));
|
||||||
if (mode != "VBR")
|
if (mode != "VBR")
|
||||||
throw SnapException("Unsupported codec mode: \"" + mode + "\". Available: \"VBR\"");
|
throw SnapException("Unsupported codec mode: \"" + mode + R"(". Available: "VBR")");
|
||||||
|
|
||||||
string qual = utils::string::trim_copy(codecOptions_.substr(codecOptions_.find(":") + 1));
|
string qual = utils::string::trim_copy(codecOptions_.substr(codecOptions_.find(':') + 1));
|
||||||
double quality = 1.0;
|
double quality = 1.0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -216,7 +216,7 @@ void OggEncoder::initEncoder()
|
||||||
mode that libVorbis does not support (eg, too low a bitrate, etc,
|
mode that libVorbis does not support (eg, too low a bitrate, etc,
|
||||||
will return 'OV_EIMPL') */
|
will return 'OV_EIMPL') */
|
||||||
|
|
||||||
if (ret)
|
if (ret != 0)
|
||||||
throw SnapException("failed to init encoder");
|
throw SnapException("failed to init encoder");
|
||||||
|
|
||||||
/* add a comment */
|
/* add a comment */
|
||||||
|
@ -262,7 +262,7 @@ void OggEncoder::initEncoder()
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
break;
|
break;
|
||||||
headerChunk_->payloadSize += og_.header_len + og_.body_len;
|
headerChunk_->payloadSize += og_.header_len + og_.body_len;
|
||||||
headerChunk_->payload = (char*)realloc(headerChunk_->payload, headerChunk_->payloadSize);
|
headerChunk_->payload = static_cast<char*>(realloc(headerChunk_->payload, headerChunk_->payloadSize));
|
||||||
LOG(DEBUG, LOG_TAG) << "HeadLen: " << og_.header_len << ", bodyLen: " << og_.body_len << ", result: " << result << "\n";
|
LOG(DEBUG, LOG_TAG) << "HeadLen: " << og_.header_len << ", bodyLen: " << og_.body_len << ", result: " << result << "\n";
|
||||||
memcpy(headerChunk_->payload + pos, og_.header, og_.header_len);
|
memcpy(headerChunk_->payload + pos, og_.header, og_.header_len);
|
||||||
pos += og_.header_len;
|
pos += og_.header_len;
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2015 Hannes Ellinger
|
Copyright (C) 2015 Hannes Ellinger
|
||||||
|
Copyright (C) 2016-2021 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
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
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 "opus_encoder.hpp"
|
#include "opus_encoder.hpp"
|
||||||
|
@ -157,7 +158,7 @@ void OpusEncoder::initEncoder()
|
||||||
|
|
||||||
// create some opus pseudo header to let the decoder know about the sample format
|
// create some opus pseudo header to let the decoder know about the sample format
|
||||||
headerChunk_->payloadSize = 12;
|
headerChunk_->payloadSize = 12;
|
||||||
headerChunk_->payload = (char*)realloc(headerChunk_->payload, headerChunk_->payloadSize);
|
headerChunk_->payload = static_cast<char*>(realloc(headerChunk_->payload, headerChunk_->payloadSize));
|
||||||
char* payload = headerChunk_->payload;
|
char* payload = headerChunk_->payload;
|
||||||
assign(payload, SWAP_32(ID_OPUS));
|
assign(payload, SWAP_32(ID_OPUS));
|
||||||
assign(payload + 4, SWAP_32(sampleFormat_.rate()));
|
assign(payload + 4, SWAP_32(sampleFormat_.rate()));
|
||||||
|
@ -249,9 +250,9 @@ void OpusEncoder::encode(const SampleFormat& format, const char* data, size_t si
|
||||||
// copy encoded data to chunk
|
// copy encoded data to chunk
|
||||||
auto opusChunk = make_shared<msg::PcmChunk>(format, 0);
|
auto opusChunk = make_shared<msg::PcmChunk>(format, 0);
|
||||||
opusChunk->payloadSize = len;
|
opusChunk->payloadSize = len;
|
||||||
opusChunk->payload = (char*)realloc(opusChunk->payload, opusChunk->payloadSize);
|
opusChunk->payload = static_cast<char*>(realloc(opusChunk->payload, opusChunk->payloadSize));
|
||||||
memcpy(opusChunk->payload, encoded_.data(), len);
|
memcpy(opusChunk->payload, encoded_.data(), len);
|
||||||
encoded_callback_(*this, opusChunk, (double)samples_per_channel / sampleFormat_.msRate());
|
encoded_callback_(*this, opusChunk, static_cast<double>(samples_per_channel) / sampleFormat_.msRate());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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,7 +58,7 @@ void PcmEncoder::encode(const msg::PcmChunk& chunk)
|
||||||
void PcmEncoder::initEncoder()
|
void PcmEncoder::initEncoder()
|
||||||
{
|
{
|
||||||
headerChunk_->payloadSize = 44;
|
headerChunk_->payloadSize = 44;
|
||||||
headerChunk_->payload = (char*)realloc(headerChunk_->payload, headerChunk_->payloadSize);
|
headerChunk_->payload = static_cast<char*>(realloc(headerChunk_->payload, headerChunk_->payloadSize));
|
||||||
char* payload = headerChunk_->payload;
|
char* payload = headerChunk_->payload;
|
||||||
assign(payload, SWAP_32(ID_RIFF));
|
assign(payload, SWAP_32(ID_RIFF));
|
||||||
assign(payload + 4, SWAP_32(36));
|
assign(payload + 4, SWAP_32(36));
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
/***
|
/***
|
||||||
This file is part of avahi.
|
This file is part of snapcast
|
||||||
|
Copyright (C) 2014-2021 Johannes Pohl
|
||||||
|
|
||||||
avahi is free software; you can redistribute it and/or modify it
|
This program is free software: you can redistribute it and/or modify
|
||||||
under the terms of the GNU Lesser General Public License as
|
it under the terms of the GNU General Public License as published by
|
||||||
published by the Free Software Foundation; either version 2.1 of the
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
License, or (at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
avahi is distributed in the hope that it will be useful, but WITHOUT
|
This program is distributed in the hope that it will be useful,
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU General Public License
|
||||||
License along with avahi; if not, write to the Free Software
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
||||||
USA.
|
|
||||||
***/
|
***/
|
||||||
|
|
||||||
#include "publish_avahi.hpp"
|
#include "publish_avahi.hpp"
|
||||||
|
@ -42,7 +41,7 @@ void PublishAvahi::publish(const std::vector<mDNSService>& services)
|
||||||
services_ = services;
|
services_ = services;
|
||||||
|
|
||||||
/// Allocate main loop object
|
/// Allocate main loop object
|
||||||
if (!(simple_poll = avahi_simple_poll_new()))
|
if ((simple_poll = avahi_simple_poll_new()) == nullptr)
|
||||||
{
|
{
|
||||||
/// TODO: error handling
|
/// TODO: error handling
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to create simple poll object.\n";
|
LOG(ERROR, LOG_TAG) << "Failed to create simple poll object.\n";
|
||||||
|
@ -53,7 +52,7 @@ void PublishAvahi::publish(const std::vector<mDNSService>& services)
|
||||||
client_ = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_IGNORE_USER_CONFIG, client_callback, this, &error);
|
client_ = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_IGNORE_USER_CONFIG, client_callback, this, &error);
|
||||||
|
|
||||||
/// Check wether creating the client object succeeded
|
/// Check wether creating the client object succeeded
|
||||||
if (!client_)
|
if (client_ == nullptr)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to create client: " << avahi_strerror(error) << "\n";
|
LOG(ERROR, LOG_TAG) << "Failed to create client: " << avahi_strerror(error) << "\n";
|
||||||
}
|
}
|
||||||
|
@ -76,10 +75,10 @@ PublishAvahi::~PublishAvahi()
|
||||||
{
|
{
|
||||||
timer_.cancel();
|
timer_.cancel();
|
||||||
|
|
||||||
if (client_)
|
if (client_ != nullptr)
|
||||||
avahi_client_free(client_);
|
avahi_client_free(client_);
|
||||||
|
|
||||||
if (simple_poll)
|
if (simple_poll != nullptr)
|
||||||
avahi_simple_poll_free(simple_poll);
|
avahi_simple_poll_free(simple_poll);
|
||||||
|
|
||||||
avahi_free(name);
|
avahi_free(name);
|
||||||
|
@ -134,9 +133,9 @@ void PublishAvahi::create_services(AvahiClient* c)
|
||||||
char* n;
|
char* n;
|
||||||
|
|
||||||
/// If this is the first time we're called, let's create a new entry group if necessary
|
/// If this is the first time we're called, let's create a new entry group if necessary
|
||||||
if (!group)
|
if (group == nullptr)
|
||||||
{
|
{
|
||||||
if (!(group = avahi_entry_group_new(c, entry_group_callback, this)))
|
if ((group = avahi_entry_group_new(c, entry_group_callback, this)) == nullptr)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c)) << "\n";
|
LOG(ERROR, LOG_TAG) << "avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c)) << "\n";
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -145,7 +144,7 @@ void PublishAvahi::create_services(AvahiClient* c)
|
||||||
|
|
||||||
/// If the group is empty (either because it was just created, or because it was reset previously, add our entries.
|
/// If the group is empty (either because it was just created, or because it was reset previously, add our entries.
|
||||||
int ret;
|
int ret;
|
||||||
if (avahi_entry_group_is_empty(group))
|
if (avahi_entry_group_is_empty(group) != 0)
|
||||||
{
|
{
|
||||||
LOG(INFO, LOG_TAG) << "Adding service '" << name << "'\n";
|
LOG(INFO, LOG_TAG) << "Adding service '" << name << "'\n";
|
||||||
|
|
||||||
|
@ -230,7 +229,7 @@ void PublishAvahi::client_callback(AvahiClient* c, AvahiClientState state, AVAHI
|
||||||
/// The server records are now being established. This might be caused by a host name change. We need to wait
|
/// The server records are now being established. This might be caused by a host name change. We need to wait
|
||||||
/// for our own records to register until the host name is properly esatblished.
|
/// for our own records to register until the host name is properly esatblished.
|
||||||
|
|
||||||
if (group)
|
if (group != nullptr)
|
||||||
avahi_entry_group_reset(group);
|
avahi_entry_group_reset(group);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -250,7 +250,7 @@ void Server::processRequest(const jsonrpcpp::request_ptr request, jsonrpcpp::ent
|
||||||
group->muted = muted;
|
group->muted = muted;
|
||||||
|
|
||||||
/// Update clients
|
/// Update clients
|
||||||
for (auto client : group->clients)
|
for (const auto& client : group->clients)
|
||||||
{
|
{
|
||||||
session_ptr session = streamServer_->getStreamSession(client->id);
|
session_ptr session = streamServer_->getStreamSession(client->id);
|
||||||
if (session != nullptr)
|
if (session != nullptr)
|
||||||
|
@ -283,7 +283,7 @@ void Server::processRequest(const jsonrpcpp::request_ptr request, jsonrpcpp::ent
|
||||||
group->streamId = streamId;
|
group->streamId = streamId;
|
||||||
|
|
||||||
// Update clients
|
// Update clients
|
||||||
for (auto client : group->clients)
|
for (const auto& client : group->clients)
|
||||||
{
|
{
|
||||||
session_ptr session = streamServer_->getStreamSession(client->id);
|
session_ptr session = streamServer_->getStreamSession(client->id);
|
||||||
if (session && (session->pcmStream() != stream))
|
if (session && (session->pcmStream() != stream))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -209,7 +209,7 @@ int main(int argc, char* argv[])
|
||||||
string logformat = "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)";
|
string logformat = "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)";
|
||||||
if (settings.logging.sink.find("file:") != string::npos)
|
if (settings.logging.sink.find("file:") != string::npos)
|
||||||
{
|
{
|
||||||
string logfile = settings.logging.sink.substr(settings.logging.sink.find(":") + 1);
|
string logfile = settings.logging.sink.substr(settings.logging.sink.find(':') + 1);
|
||||||
AixLog::Log::init<AixLog::SinkFile>(logfilter, logfile, logformat);
|
AixLog::Log::init<AixLog::SinkFile>(logfilter, logfile, logformat);
|
||||||
}
|
}
|
||||||
else if (settings.logging.sink == "stdout")
|
else if (settings.logging.sink == "stdout")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -75,7 +75,7 @@ void StreamServer::onMetaChanged(const PcmStream* pcmStream, std::shared_ptr<msg
|
||||||
// Send meta to all connected clients
|
// Send meta to all connected clients
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
||||||
for (auto s : sessions_)
|
for (const auto& s : sessions_)
|
||||||
{
|
{
|
||||||
if (auto session = s.lock())
|
if (auto session = s.lock())
|
||||||
{
|
{
|
||||||
|
@ -95,12 +95,12 @@ void StreamServer::onChunkEncoded(const PcmStream* pcmStream, bool isDefaultStre
|
||||||
std::vector<std::shared_ptr<StreamSession>> sessions;
|
std::vector<std::shared_ptr<StreamSession>> sessions;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
||||||
for (auto session : sessions_)
|
for (const auto& session : sessions_)
|
||||||
if (auto s = session.lock())
|
if (auto s = session.lock())
|
||||||
sessions.push_back(s);
|
sessions.push_back(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto session : sessions)
|
for (const auto& session : sessions)
|
||||||
{
|
{
|
||||||
if (!settings_.stream.sendAudioToMutedClients)
|
if (!settings_.stream.sendAudioToMutedClients)
|
||||||
{
|
{
|
||||||
|
@ -131,7 +131,7 @@ void StreamServer::onChunkEncoded(const PcmStream* pcmStream, bool isDefaultStre
|
||||||
|
|
||||||
void StreamServer::onMessageReceived(StreamSession* streamSession, const msg::BaseMessage& baseMessage, char* buffer)
|
void StreamServer::onMessageReceived(StreamSession* streamSession, const msg::BaseMessage& baseMessage, char* buffer)
|
||||||
{
|
{
|
||||||
if (messageReceiver_)
|
if (messageReceiver_ != nullptr)
|
||||||
messageReceiver_->onMessageReceived(streamSession, baseMessage, buffer);
|
messageReceiver_->onMessageReceived(streamSession, baseMessage, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ void StreamServer::onDisconnect(StreamSession* streamSession)
|
||||||
}),
|
}),
|
||||||
sessions_.end());
|
sessions_.end());
|
||||||
LOG(DEBUG, LOG_TAG) << "sessions: " << sessions_.size() << "\n";
|
LOG(DEBUG, LOG_TAG) << "sessions: " << sessions_.size() << "\n";
|
||||||
if (messageReceiver_)
|
if (messageReceiver_ != nullptr)
|
||||||
messageReceiver_->onDisconnect(streamSession);
|
messageReceiver_->onDisconnect(streamSession);
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ session_ptr StreamServer::getStreamSession(StreamSession* streamSession) const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
||||||
|
|
||||||
for (auto session : sessions_)
|
for (const auto& session : sessions_)
|
||||||
{
|
{
|
||||||
if (auto s = session.lock())
|
if (auto s = session.lock())
|
||||||
if (s.get() == streamSession)
|
if (s.get() == streamSession)
|
||||||
|
@ -177,7 +177,7 @@ session_ptr StreamServer::getStreamSession(const std::string& clientId) const
|
||||||
{
|
{
|
||||||
// LOG(INFO, LOG_TAG) << "getStreamSession: " << mac << "\n";
|
// LOG(INFO, LOG_TAG) << "getStreamSession: " << mac << "\n";
|
||||||
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
||||||
for (auto session : sessions_)
|
for (const auto& session : sessions_)
|
||||||
{
|
{
|
||||||
if (auto s = session.lock())
|
if (auto s = session.lock())
|
||||||
if (s->clientId == clientId)
|
if (s->clientId == clientId)
|
||||||
|
@ -254,7 +254,7 @@ void StreamServer::stop()
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
||||||
cleanup();
|
cleanup();
|
||||||
for (auto s : sessions_)
|
for (const auto& s : sessions_)
|
||||||
{
|
{
|
||||||
if (auto session = s.lock())
|
if (auto session = s.lock())
|
||||||
session->stop();
|
session->stop();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -111,7 +111,7 @@ void StreamSessionWebsocket::on_read_ws(beast::error_code ec, std::size_t bytes_
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = boost::asio::buffer_cast<char*>(buffer_.data());
|
auto* data = boost::asio::buffer_cast<char*>(buffer_.data());
|
||||||
baseMessage_.deserialize(data);
|
baseMessage_.deserialize(data);
|
||||||
LOG(DEBUG, LOG_TAG) << "getNextMessage: " << baseMessage_.type << ", size: " << baseMessage_.size << ", id: " << baseMessage_.id
|
LOG(DEBUG, LOG_TAG) << "getNextMessage: " << baseMessage_.type << ", size: " << baseMessage_.size << ", id: " << baseMessage_.id
|
||||||
<< ", refers: " << baseMessage_.refersTo << "\n";
|
<< ", refers: " << baseMessage_.refersTo << "\n";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -38,7 +38,7 @@ string hex2str(string input)
|
||||||
using byte = unsigned char;
|
using byte = unsigned char;
|
||||||
unsigned long x = strtoul(input.c_str(), nullptr, 16);
|
unsigned long x = strtoul(input.c_str(), nullptr, 16);
|
||||||
byte a[] = {byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x), 0};
|
byte a[] = {byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x), 0};
|
||||||
return string((char*)a);
|
return string(reinterpret_cast<char*>(a));
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ int AirplayStream::parse(string line)
|
||||||
{
|
{
|
||||||
enum XML_Status result;
|
enum XML_Status result;
|
||||||
|
|
||||||
if ((result = XML_Parse(parser_, line.c_str(), line.length(), false)) == XML_STATUS_ERROR)
|
if ((result = XML_Parse(parser_, line.c_str(), line.length(), 0)) == XML_STATUS_ERROR)
|
||||||
{
|
{
|
||||||
XML_ParserFree(parser_);
|
XML_ParserFree(parser_);
|
||||||
createParser();
|
createParser();
|
||||||
|
@ -288,10 +288,10 @@ void AirplayStream::initExeAndPath(const string& filename)
|
||||||
throw SnapException("shairport-sync not found");
|
throw SnapException("shairport-sync not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exe_.find("/") != string::npos)
|
if (exe_.find('/') != string::npos)
|
||||||
{
|
{
|
||||||
path_ = exe_.substr(0, exe_.find_last_of("/") + 1);
|
path_ = exe_.substr(0, exe_.find_last_of('/') + 1);
|
||||||
exe_ = exe_.substr(exe_.find_last_of("/") + 1);
|
exe_ = exe_.substr(exe_.find_last_of('/') + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,14 +317,14 @@ void AirplayStream::onStderrMsg(const std::string& line)
|
||||||
#ifdef HAS_EXPAT
|
#ifdef HAS_EXPAT
|
||||||
void XMLCALL AirplayStream::element_start(void* userdata, const char* element_name, const char** attr)
|
void XMLCALL AirplayStream::element_start(void* userdata, const char* element_name, const char** attr)
|
||||||
{
|
{
|
||||||
AirplayStream* self = (AirplayStream*)userdata;
|
auto* self = static_cast<AirplayStream*>(userdata);
|
||||||
string name(element_name);
|
string name(element_name);
|
||||||
|
|
||||||
self->buf_.assign("");
|
self->buf_.assign("");
|
||||||
if (name == "item")
|
if (name == "item")
|
||||||
self->entry_.reset(new TageEntry);
|
self->entry_.reset(new TageEntry);
|
||||||
|
|
||||||
for (int i = 0; attr[i]; i += 2)
|
for (int i = 0; attr[i] != nullptr; i += 2)
|
||||||
{
|
{
|
||||||
string name(attr[i]);
|
string name(attr[i]);
|
||||||
string value(attr[i + 1]);
|
string value(attr[i + 1]);
|
||||||
|
@ -335,7 +335,7 @@ void XMLCALL AirplayStream::element_start(void* userdata, const char* element_na
|
||||||
|
|
||||||
void XMLCALL AirplayStream::element_end(void* userdata, const char* element_name)
|
void XMLCALL AirplayStream::element_end(void* userdata, const char* element_name)
|
||||||
{
|
{
|
||||||
AirplayStream* self = (AirplayStream*)userdata;
|
auto* self = static_cast<AirplayStream*>(userdata);
|
||||||
string name(element_name);
|
string name(element_name);
|
||||||
|
|
||||||
if (name == "code")
|
if (name == "code")
|
||||||
|
@ -361,8 +361,8 @@ void XMLCALL AirplayStream::element_end(void* userdata, const char* element_name
|
||||||
|
|
||||||
void XMLCALL AirplayStream::data(void* userdata, const char* content, int length)
|
void XMLCALL AirplayStream::data(void* userdata, const char* content, int length)
|
||||||
{
|
{
|
||||||
AirplayStream* self = (AirplayStream*)userdata;
|
auto* self = static_cast<AirplayStream*>(userdata);
|
||||||
string value(content, (size_t)length);
|
string value(content, static_cast<size_t>(length));
|
||||||
self->buf_.append(value);
|
self->buf_.append(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -162,7 +162,7 @@ void AlsaStream::initAlsa()
|
||||||
|
|
||||||
void AlsaStream::uninitAlsa()
|
void AlsaStream::uninitAlsa()
|
||||||
{
|
{
|
||||||
if (handle_)
|
if (handle_ != nullptr)
|
||||||
{
|
{
|
||||||
snd_pcm_close(handle_);
|
snd_pcm_close(handle_);
|
||||||
handle_ = nullptr;
|
handle_ = nullptr;
|
||||||
|
|
|
@ -33,7 +33,7 @@ static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
static inline bool is_base64(unsigned char c)
|
static inline bool is_base64(unsigned char c)
|
||||||
{
|
{
|
||||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
return ((isalnum(c) != 0) || (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)
|
||||||
|
@ -44,7 +44,7 @@ std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_
|
||||||
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--) != 0u)
|
||||||
{
|
{
|
||||||
char_array_3[i++] = *(bytes_to_encode++);
|
char_array_3[i++] = *(bytes_to_encode++);
|
||||||
if (i == 3)
|
if (i == 3)
|
||||||
|
@ -60,7 +60,7 @@ std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i)
|
if (i != 0)
|
||||||
{
|
{
|
||||||
for (j = i; j < 3; j++)
|
for (j = i; j < 3; j++)
|
||||||
char_array_3[j] = '\0';
|
char_array_3[j] = '\0';
|
||||||
|
@ -88,7 +88,7 @@ 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--) != 0) && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
|
||||||
{
|
{
|
||||||
char_array_4[i++] = encoded_string[in_];
|
char_array_4[i++] = encoded_string[in_];
|
||||||
in_++;
|
in_++;
|
||||||
|
@ -107,7 +107,7 @@ std::string base64_decode(std::string const& encoded_string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i)
|
if (i != 0)
|
||||||
{
|
{
|
||||||
for (j = i; j < 4; j++)
|
for (j = i; j < 4; j++)
|
||||||
char_array_4[j] = 0;
|
char_array_4[j] = 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -49,7 +49,7 @@ LibrespotStream::LibrespotStream(PcmListener* pcmListener, boost::asio::io_conte
|
||||||
killall_ = (uri_.getQuery("killall", "false") == "true");
|
killall_ = (uri_.getQuery("killall", "false") == "true");
|
||||||
|
|
||||||
if (username.empty() != password.empty())
|
if (username.empty() != password.empty())
|
||||||
throw SnapException("missing parameter \"username\" or \"password\" (must provide both, or neither)");
|
throw SnapException(R"(missing parameter "username" or "password" (must provide both, or neither))");
|
||||||
|
|
||||||
if (!params_.empty())
|
if (!params_.empty())
|
||||||
params_ += " ";
|
params_ += " ";
|
||||||
|
@ -90,10 +90,10 @@ void LibrespotStream::initExeAndPath(const std::string& filename)
|
||||||
throw SnapException("librespot not found");
|
throw SnapException("librespot not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exe_.find("/") != string::npos)
|
if (exe_.find('/') != string::npos)
|
||||||
{
|
{
|
||||||
path_ = exe_.substr(0, exe_.find_last_of("/") + 1);
|
path_ = exe_.substr(0, exe_.find_last_of('/') + 1);
|
||||||
exe_ = exe_.substr(exe_.find_last_of("/") + 1);
|
exe_ = exe_.substr(exe_.find_last_of('/') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (killall_)
|
if (killall_)
|
||||||
|
@ -149,7 +149,7 @@ void LibrespotStream::onStderrMsg(const std::string& line)
|
||||||
{
|
{
|
||||||
LOG(INFO, LOG_TAG) << "metadata: <" << m[1] << ">\n";
|
LOG(INFO, LOG_TAG) << "metadata: <" << m[1] << ">\n";
|
||||||
|
|
||||||
json jtag = {{"TITLE", (string)m[1]}};
|
json jtag = {{"TITLE", string(m[1])}};
|
||||||
setMeta(jtag);
|
setMeta(jtag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -130,7 +130,7 @@ void PcmStream::setState(ReaderState newState)
|
||||||
state_ = newState;
|
state_ = newState;
|
||||||
for (auto* listener : pcmListeners_)
|
for (auto* listener : pcmListeners_)
|
||||||
{
|
{
|
||||||
if (listener)
|
if (listener != nullptr)
|
||||||
listener->onStateChanged(this, newState);
|
listener->onStateChanged(this, newState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ void PcmStream::chunkEncoded(const encoder::Encoder& encoder, std::shared_ptr<ms
|
||||||
tvEncodedChunk_ += std::chrono::nanoseconds(static_cast<std::chrono::nanoseconds::rep>(duration * 1000000));
|
tvEncodedChunk_ += std::chrono::nanoseconds(static_cast<std::chrono::nanoseconds::rep>(duration * 1000000));
|
||||||
for (auto* listener : pcmListeners_)
|
for (auto* listener : pcmListeners_)
|
||||||
{
|
{
|
||||||
if (listener)
|
if (listener != nullptr)
|
||||||
listener->onChunkEncoded(this, chunk, duration);
|
listener->onChunkEncoded(this, chunk, duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ void PcmStream::chunkRead(const msg::PcmChunk& chunk)
|
||||||
{
|
{
|
||||||
for (auto* listener : pcmListeners_)
|
for (auto* listener : pcmListeners_)
|
||||||
{
|
{
|
||||||
if (listener)
|
if (listener != nullptr)
|
||||||
listener->onChunkRead(this, chunk);
|
listener->onChunkRead(this, chunk);
|
||||||
}
|
}
|
||||||
encoder_->encode(chunk);
|
encoder_->encode(chunk);
|
||||||
|
@ -175,7 +175,7 @@ void PcmStream::resync(const std::chrono::nanoseconds& duration)
|
||||||
{
|
{
|
||||||
for (auto* listener : pcmListeners_)
|
for (auto* listener : pcmListeners_)
|
||||||
{
|
{
|
||||||
if (listener)
|
if (listener != nullptr)
|
||||||
listener->onResync(this, duration.count() / 1000000.);
|
listener->onResync(this, duration.count() / 1000000.);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ void PcmStream::setMeta(const json& jtag)
|
||||||
// Trigger a stream update
|
// Trigger a stream update
|
||||||
for (auto* listener : pcmListeners_)
|
for (auto* listener : pcmListeners_)
|
||||||
{
|
{
|
||||||
if (listener)
|
if (listener != nullptr)
|
||||||
listener->onMetaChanged(this);
|
listener->onMetaChanged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -43,7 +43,7 @@ PipeStream::PipeStream(PcmListener* pcmListener, boost::asio::io_context& ioc, c
|
||||||
|
|
||||||
LOG(INFO, LOG_TAG) << "PipeStream mode: " << mode << "\n";
|
LOG(INFO, LOG_TAG) << "PipeStream mode: " << mode << "\n";
|
||||||
if ((mode != "read") && (mode != "create"))
|
if ((mode != "read") && (mode != "create"))
|
||||||
throw SnapException("create mode for fifo must be \"read\" or \"create\"");
|
throw SnapException(R"(create mode for fifo must be "read" or "create")");
|
||||||
|
|
||||||
if (mode == "create")
|
if (mode == "create")
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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,8 +22,8 @@
|
||||||
#include "common/snap_exception.hpp"
|
#include "common/snap_exception.hpp"
|
||||||
#include "common/utils.hpp"
|
#include "common/utils.hpp"
|
||||||
#include "common/utils/string_utils.hpp"
|
#include "common/utils/string_utils.hpp"
|
||||||
|
#include <climits>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ std::string ProcessStream::findExe(const std::string& filename) const
|
||||||
return filename;
|
return filename;
|
||||||
|
|
||||||
std::string exe = filename;
|
std::string exe = filename;
|
||||||
if (exe.find("/") != string::npos)
|
if (exe.find('/') != string::npos)
|
||||||
exe = exe.substr(exe.find_last_of("/") + 1);
|
exe = exe.substr(exe.find_last_of('/') + 1);
|
||||||
|
|
||||||
/// check with "which"
|
/// check with "which"
|
||||||
string which = execGetOutput("which " + exe);
|
string which = execGetOutput("which " + exe);
|
||||||
|
@ -85,10 +85,10 @@ void ProcessStream::initExeAndPath(const std::string& filename)
|
||||||
{
|
{
|
||||||
path_ = "";
|
path_ = "";
|
||||||
exe_ = findExe(filename);
|
exe_ = findExe(filename);
|
||||||
if (exe_.find("/") != string::npos)
|
if (exe_.find('/') != string::npos)
|
||||||
{
|
{
|
||||||
path_ = exe_.substr(0, exe_.find_last_of("/") + 1);
|
path_ = exe_.substr(0, exe_.find_last_of('/') + 1);
|
||||||
exe_ = exe_.substr(exe_.find_last_of("/") + 1);
|
exe_ = exe_.substr(exe_.find_last_of('/') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fileExists(path_ + exe_))
|
if (!fileExists(path_ + exe_))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2020 Johannes Pohl
|
Copyright (C) 2014-2021 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
|
||||||
|
@ -202,7 +202,7 @@ void StreamManager::stop()
|
||||||
json StreamManager::toJson() const
|
json StreamManager::toJson() const
|
||||||
{
|
{
|
||||||
json result = json::array();
|
json result = json::array();
|
||||||
for (auto stream : streams_)
|
for (const auto& stream : streams_)
|
||||||
if (stream->getCodec() != "null")
|
if (stream->getCodec() != "null")
|
||||||
result.push_back(stream->toJson());
|
result.push_back(stream->toJson());
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue