Add documentation

This commit is contained in:
badaix 2025-02-16 22:07:09 +01:00 committed by Johannes Pohl
parent f0985cbce4
commit 76e35e3e18
34 changed files with 199 additions and 78 deletions

View file

@ -153,6 +153,7 @@ public:
virtual void getNextMessage(const MessageHandler<msg::BaseMessage>& handler) = 0;
protected:
/// Send @p buffer, return result in @p write_handler
virtual void write(boost::asio::streambuf& buffer, WriteHandler&& write_handler) = 0;
/// Connect to @p endpoint

View file

@ -129,7 +129,7 @@ Controller::Controller(boost::asio::io_context& io_context, const ClientSettings
#endif // HAS_OPENSSL
}
/// Helper to create a player instance
template <typename PlayerType>
std::unique_ptr<Player> Controller::createPlayer(ClientSettings::Player& settings, const std::string& player_name)
{

View file

@ -46,8 +46,8 @@ struct riff_wave_header
/// See https://en.wikipedia.org/wiki/WAV
struct chunk_header
{
uint32_t id;
uint32_t sz;
uint32_t id; ///< id
uint32_t sz; ///< size
};
@ -55,12 +55,12 @@ struct chunk_header
/// See https://en.wikipedia.org/wiki/WAV
struct chunk_fmt
{
uint16_t audio_format; ///<
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
uint16_t audio_format; ///< format
uint16_t num_channels; ///< channels
uint32_t sample_rate; ///< sample rate
uint32_t byte_rate; ///< byte rate
uint16_t block_align; ///< block align
uint16_t bits_per_sample; ///< bps
};

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2024 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -36,10 +36,12 @@ template <class T>
class DoubleBuffer
{
public:
DoubleBuffer(size_t size = 10) : bufferSize(size)
/// c'tor
explicit DoubleBuffer(size_t size = 10) : bufferSize(size)
{
}
/// Add @p element, pop last, if buffer is full
inline void add(const T& element)
{
buffer.push_back(element);
@ -47,6 +49,7 @@ public:
buffer.pop_front();
}
/// Add @p element, pop last, if buffer is full
inline void add(T&& element)
{
buffer.push_back(std::move(element));
@ -54,7 +57,7 @@ public:
buffer.pop_front();
}
/// Median as mean over N values around the median
/// @return median as mean over N values around the median
T median(uint16_t mean = 1) const
{
if (buffer.empty())
@ -78,6 +81,7 @@ public:
}
}
/// @return mean value
double mean() const
{
if (buffer.empty())
@ -88,6 +92,7 @@ public:
return mean;
}
/// @return @p percentile percentile
T percentile(unsigned int percentile) const
{
if (buffer.empty())
@ -97,6 +102,7 @@ public:
return tmpBuffer[(size_t)((tmpBuffer.size() - 1) * ((float)percentile / (float)100))];
}
/// @return array of different percentiles
template <std::size_t Size>
std::array<T, Size> percentiles(std::array<uint8_t, Size> percentiles) const
{
@ -112,31 +118,37 @@ public:
return result;
}
/// @return if the buffer is full
inline bool full() const
{
return (buffer.size() == bufferSize);
}
/// Clear the buffer
inline void clear()
{
buffer.clear();
}
/// @return current size of the buffer
inline size_t size() const
{
return buffer.size();
}
/// @return if the buffer is empty
inline bool empty() const
{
return buffer.empty();
}
/// Set size of the buffer
void setSize(size_t size)
{
bufferSize = size;
}
/// @return the raw buffer
const std::deque<T>& getBuffer() const
{
return buffer;

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2024 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -44,7 +44,9 @@ static constexpr auto ALSA = "alsa";
class AlsaPlayer : public Player
{
public:
/// c'tor
AlsaPlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream);
/// d'tor
~AlsaPlayer() override;
void start() override;

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2022 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -16,8 +16,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef CORE_AUDIO_PLAYER_HPP
#define CORE_AUDIO_PLAYER_HPP
#pragma once
// local headers
#include "player.hpp"
@ -45,13 +45,17 @@ static constexpr auto COREAUDIO = "coreaudio";
class CoreAudioPlayer : public Player
{
public:
/// c'tor
CoreAudioPlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream);
/// d'tor
virtual ~CoreAudioPlayer();
/// Callback funtion for audio data to be played
void playerCallback(AudioQueueRef queue, AudioQueueBufferRef bufferRef);
/// @return list of available pcm devices
static std::vector<PcmDevice> pcm_list();
protected:
private:
void worker() override;
bool needsThread() const override;
@ -67,5 +71,3 @@ protected:
};
} // namespace player
#endif

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2022 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -16,8 +16,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef FILE_PLAYER_HPP
#define FILE_PLAYER_HPP
#pragma once
// local headers
#include "player.hpp"
@ -40,8 +41,10 @@ static constexpr auto FILE = "file";
class FilePlayer : public Player
{
public:
/// c'tor
FilePlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream);
virtual ~FilePlayer();
/// d'tor
~FilePlayer() override;
void start() override;
void stop() override;
@ -49,7 +52,7 @@ public:
/// List the dummy file PCM device
static std::vector<PcmDevice> pcm_list(const std::string& parameter);
protected:
private:
void requestAudio();
void loop();
bool needsThread() const override;
@ -60,5 +63,3 @@ protected:
};
} // namespace player
#endif

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2022 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -16,8 +16,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OPEN_SL_PLAYER_HPP
#define OPEN_SL_PLAYER_HPP
#pragma once
// local headers
#include "player.hpp"
@ -35,7 +35,9 @@ namespace player
static constexpr auto OPENSL = "opensl";
typedef int (*AndroidAudioCallback)(short* buffer, int num_samples);
// typedef int (*AndroidAudioCallback)(short* buffer, int num_samples);
using AndroidAudioCallback = int (*)(short*, int);
/// OpenSL Audio Player
@ -45,15 +47,18 @@ typedef int (*AndroidAudioCallback)(short* buffer, int num_samples);
class OpenslPlayer : public Player
{
public:
/// c'tor
OpenslPlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream);
virtual ~OpenslPlayer();
/// d'tor
~OpenslPlayer() override;
void start() override;
void stop() override;
/// Callback to feed data to the player API
void playerCallback(SLAndroidSimpleBufferQueueItf bq);
protected:
private:
void initOpensl();
void uninitOpensl();
@ -83,5 +88,3 @@ protected:
};
} // namespace player
#endif

View file

@ -54,6 +54,7 @@ public:
bool mute{false}; ///< muted?
};
/// Callback for volume changes on the local client, to notify the server
using volume_callback = std::function<void(const Volume& volume)>;
/// c'tor
@ -89,7 +90,6 @@ protected:
/// set the hardware mixer volume
/// @param volume the volume on range [0..1], muted or not
/// @param muted muted or not
virtual void setHardwareVolume(const Volume& volume);
/// set volume polynomial: volume^exp
@ -102,7 +102,6 @@ protected:
/// Notify the server about hardware volume changes
/// @param volume the volume in range [0..1]
/// @param muted if muted or not
void notifyVolumeChange(const Volume& volume) const
{
if (onVolumeChanged_)

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2024 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -42,7 +42,9 @@ static constexpr auto PULSE = "pulse";
class PulsePlayer : public Player
{
public:
/// c'tor
PulsePlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream);
/// d'tor
virtual ~PulsePlayer();
void start() override;
@ -51,7 +53,7 @@ public:
/// List the system's audio output devices
static std::vector<PcmDevice> pcm_list(const std::string& parameter);
protected:
private:
bool needsThread() const override;
void worker() override;

View file

@ -51,6 +51,7 @@ static constexpr auto LOG_TAG = "WASAPI";
template <typename T>
struct COMMemDeleter
{
/// Operator()
void operator()(T* obj)
{
if (obj != NULL)

View file

@ -16,8 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef WASAPI_PLAYER_HPP
#define WASAPI_PLAYER_HPP
#pragma once
#pragma warning(push)
#pragma warning(disable : 4100)
@ -42,31 +41,37 @@ class AudioSessionEventListener : public IAudioSessionEvents
bool muted_ = false;
public:
/// c'tor
AudioSessionEventListener() : _cRef(1)
{
}
/// @return volume
float getVolume()
{
return volume_;
}
/// @return if muted
bool getMuted()
{
return muted_;
}
/// d'tor
~AudioSessionEventListener()
{
}
// IUnknown methods -- AddRef, Release, and QueryInterface
/// documentation missing
ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&_cRef);
}
/// documentation missing
ULONG STDMETHODCALLTYPE Release()
{
ULONG ulRef = InterlockedDecrement(&_cRef);
@ -77,34 +82,42 @@ public:
return ulRef;
}
/// documentation missing
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface);
// Notification methods for audio session events
/// OnDisplayNameChanged callback
HRESULT STDMETHODCALLTYPE OnDisplayNameChanged(LPCWSTR NewDisplayName, LPCGUID EventContext)
{
return S_OK;
}
/// OnIconPathChanged callback
HRESULT STDMETHODCALLTYPE OnIconPathChanged(LPCWSTR NewIconPath, LPCGUID EventContext)
{
return S_OK;
}
/// OnSimpleVolumeChanged callback
HRESULT STDMETHODCALLTYPE OnSimpleVolumeChanged(float NewVolume, BOOL NewMute, LPCGUID EventContext);
/// OnChannelVolumeChanged callback
HRESULT STDMETHODCALLTYPE OnChannelVolumeChanged(DWORD ChannelCount, float NewChannelVolumeArray[], DWORD ChangedChannel, LPCGUID EventContext)
{
return S_OK;
}
/// OnGroupingParamChanged callback
HRESULT STDMETHODCALLTYPE OnGroupingParamChanged(LPCGUID NewGroupingParam, LPCGUID EventContext)
{
return S_OK;
}
/// OnStateChanged callback
HRESULT STDMETHODCALLTYPE OnStateChanged(AudioSessionState NewState);
/// OnSessionDisconnected callback
HRESULT STDMETHODCALLTYPE OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReason);
};
@ -117,19 +130,23 @@ class AudioEndpointVolumeCallback : public IAudioEndpointVolumeCallback
bool muted_ = false;
public:
/// c'tor
AudioEndpointVolumeCallback() : _cRef(1)
{
}
/// d'tor
~AudioEndpointVolumeCallback()
{
}
/// @return volume
float getVolume()
{
return volume_;
}
/// @return if muted
bool getMuted()
{
return muted_;
@ -137,11 +154,13 @@ public:
// IUnknown methods -- AddRef, Release, and QueryInterface
/// documentation missing
ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&_cRef);
}
/// documentation missing
ULONG STDMETHODCALLTYPE Release()
{
ULONG ulRef = InterlockedDecrement(&_cRef);
@ -152,6 +171,7 @@ public:
return ulRef;
}
/// documentation missing
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface)
{
if (IID_IUnknown == riid)
@ -175,6 +195,7 @@ public:
// Callback method for endpoint-volume-change notifications.
/// documentation missing
HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify);
};
@ -184,14 +205,17 @@ static constexpr auto WASAPI = "wasapi";
class WASAPIPlayer : public Player
{
public:
/// c'tor
WASAPIPlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream);
/// d'tor
virtual ~WASAPIPlayer();
/// @return list of available PCM devices
static std::vector<PcmDevice> pcm_list();
protected:
virtual void worker();
virtual bool needsThread() const override
void worker() override;
bool needsThread() const override
{
return true;
}
@ -206,5 +230,3 @@ private:
#pragma warning(pop)
} // namespace player
#endif

View file

@ -45,11 +45,14 @@
class Stream
{
public:
/// c'tor
Stream(const SampleFormat& in_format, const SampleFormat& out_format);
/// d'tor
virtual ~Stream() = default;
/// Adds PCM data to the queue
void addChunk(std::unique_ptr<msg::PcmChunk> chunk);
/// Remove all chunks from the queue
void clearChunks();
/// Get PCM data, which will be played out in "outputBufferDacTime" time
@ -68,11 +71,13 @@ public:
/// "Server buffer": playout latency, e.g. 1000ms
void setBufferLen(size_t bufferLenMs);
/// @return sampleformat
const SampleFormat& getFormat() const
{
return format_;
}
/// @return if chunk was avabilable within @p timeout
bool waitForChunk(const std::chrono::milliseconds& timeout) const;
private:

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2023 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -40,15 +40,19 @@
class TimeProvider
{
public:
/// @return singleton
static TimeProvider& getInstance()
{
static TimeProvider instance;
return instance;
}
/// Set diff to server
void setDiffToServer(double ms);
/// Set diff from round-trip-times client-to-server and server-to-client
void setDiff(const tv& c2s, const tv& s2c);
/// @return time diff to server
template <typename T>
inline T getDiffToServer() const
{
@ -60,22 +64,26 @@ public:
long getDiffToServerMs();
*/
/// @return time since epoch
template <typename T>
static T sinceEpoche(const chronos::time_point_clk& point)
{
return std::chrono::duration_cast<T>(point.time_since_epoch());
}
/// @return time_point from @p timeval
static chronos::time_point_clk toTimePoint(const tv& timeval)
{
return chronos::time_point_clk(chronos::usec(timeval.usec) + chronos::sec(timeval.sec));
}
/// @return local time
inline static chronos::time_point_clk now()
{
return chronos::clk::now();
}
/// @return server time
inline static chronos::time_point_clk serverNow()
{
return chronos::clk::now() + TimeProvider::getInstance().getDiffToServer<chronos::usec>();

View file

@ -54,6 +54,7 @@ public:
return static_cast<uint32_t>(sizeof(uint32_t) + msg.dump().size());
}
/// the json message payload
json msg;

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2024 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -39,18 +39,21 @@ namespace msg
class WireChunk : public BaseMessage
{
public:
explicit WireChunk(uint32_t size = 0) : BaseMessage(message_type::kWireChunk), payloadSize(size), payload(nullptr)
/// c'tor
explicit WireChunk(uint32_t size = 0) : BaseMessage(message_type::kWireChunk), payloadSize(size)
{
if (size > 0)
payload = static_cast<char*>(malloc(size * sizeof(char)));
}
/// c'tor
WireChunk(const WireChunk& wireChunk) : BaseMessage(message_type::kWireChunk), timestamp(wireChunk.timestamp), payloadSize(wireChunk.payloadSize)
{
payload = static_cast<char*>(malloc(payloadSize));
memcpy(payload, wireChunk.payload, payloadSize);
}
/// d'tor
~WireChunk() override
{
free(payload);
@ -68,15 +71,17 @@ public:
return sizeof(tv) + sizeof(int32_t) + payloadSize;
}
/// @return playout time of the chunk (server time)
virtual chronos::time_point_clk start() const
{
return chronos::time_point_clk(chronos::sec(timestamp.sec) + chronos::usec(timestamp.usec));
}
tv timestamp;
uint32_t payloadSize;
char* payload;
tv timestamp; ///< playout timestamp (server time)
uint32_t payloadSize; ///< size of the payload
char* payload{nullptr}; ///< raw chunk payload
/// @return tuple of payload and payload size
template <typename T>
std::pair<T*, size_t> getPayload() const
{

View file

@ -30,6 +30,12 @@ template <typename T>
class Queue
{
public:
/// c'tor
Queue() = default;
Queue(const Queue&) = delete; ///< disable copying
Queue& operator=(const Queue&) = delete; ///< disable assignment
/// @return next element, delete from queue
T pop()
{
std::unique_lock<std::mutex> mlock(mutex_);
@ -41,6 +47,7 @@ public:
return val;
}
/// abort wait
void abort_wait()
{
{
@ -50,6 +57,7 @@ public:
cond_.notify_one();
}
/// wait for @p timeout for new element, @return if an element has been added
bool wait_for(const std::chrono::microseconds& timeout) const
{
std::unique_lock<std::mutex> mlock(mutex_);
@ -60,6 +68,7 @@ public:
return !queue_.empty() && !abort_;
}
/// @return if an element has been returned in @p item within @p timeout
bool try_pop(T& item, const std::chrono::microseconds& timeout = std::chrono::microseconds(0))
{
std::unique_lock<std::mutex> mlock(mutex_);
@ -79,6 +88,7 @@ public:
return true;
}
/// return next element in @p item, wait for an element if queue is empty
void pop(T& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
@ -89,6 +99,7 @@ public:
queue_.pop_front();
}
/// Add @p item to the queue
void push_front(const T& item)
{
{
@ -98,6 +109,7 @@ public:
cond_.notify_one();
}
/// return a copy of the next element in @p copy, @return false if the queue is empty
bool back_copy(T& copy)
{
std::lock_guard<std::mutex> mlock(mutex_);
@ -107,6 +119,7 @@ public:
return true;
}
/// return a copy of the last element in @p copy, @return false if the queue is empty
bool front_copy(T& copy)
{
std::lock_guard<std::mutex> mlock(mutex_);
@ -116,6 +129,7 @@ public:
return true;
}
/// Add element @p item at the front of the queue
void push_front(T&& item)
{
{
@ -125,6 +139,7 @@ public:
cond_.notify_one();
}
/// Add element @p item at the end of the queue
void push(const T& item)
{
{
@ -134,6 +149,7 @@ public:
cond_.notify_one();
}
/// Add element @p item at the end of the queue
void push(T&& item)
{
{
@ -143,21 +159,19 @@ public:
cond_.notify_one();
}
/// @return number of elements in the queue
size_t size() const
{
std::lock_guard<std::mutex> mlock(mutex_);
return queue_.size();
}
/// @return if the queue is empty
bool empty() const
{
return (size() == 0);
}
Queue() = default;
Queue(const Queue&) = delete; // disable copying
Queue& operator=(const Queue&) = delete; // disable assignment
private:
std::deque<T> queue_;
mutable std::atomic<bool> abort_;

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2024 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,7 +21,9 @@
// local headers
#include "common/aixlog.hpp"
#ifndef HAS_SOXR
#include "common/snap_exception.hpp"
#endif
// standard headers
#include <cmath>
@ -195,7 +197,7 @@ std::shared_ptr<msg::PcmChunk> Resampler::resample(const msg::PcmChunk& chunk)
}
shared_ptr<msg::PcmChunk> Resampler::resample(shared_ptr<msg::PcmChunk> chunk)
std::shared_ptr<msg::PcmChunk> Resampler::resample(std::shared_ptr<msg::PcmChunk> chunk)
{
#ifndef HAS_SOXR
return chunk;

View file

@ -38,57 +38,70 @@
class SampleFormat
{
public:
/// c'tor
SampleFormat();
/// c'tor
SampleFormat(const std::string& format);
/// c'tor
SampleFormat(uint32_t rate, uint16_t bits, uint16_t channels);
/// @return sampleformat as string rate:bits::channels
std::string toString() const;
/// Set @p format (rate:bits::channels)
void setFormat(const std::string& format);
/// Set format
void setFormat(uint32_t rate, uint16_t bits, uint16_t channels);
/// @return if has format
bool isInitialized() const
{
return ((rate_ != 0) || (bits_ != 0) || (channels_ != 0));
}
/// @return rate
uint32_t rate() const
{
return rate_;
}
/// @return bits
uint16_t bits() const
{
return bits_;
}
/// @return channels
uint16_t channels() const
{
return channels_;
}
// size in [bytes] of a single mono sample, e.g. 2 bytes (= 16 bits)
/// @return size in [bytes] of a single mono sample, e.g. 2 bytes (= 16 bits)
uint16_t sampleSize() const
{
return sample_size_;
}
// size in [bytes] of a frame (sum of sample sizes = #channel*sampleSize), e.g. 4 bytes (= 2 channel * 16 bit)
/// @return size in [bytes] of a frame (sum of sample sizes = num-channel*sampleSize), e.g. 4 bytes (= 2 channel * 16 bit)
uint16_t frameSize() const
{
return frame_size_;
}
/// @return rate per ms (= rate / 1000)
inline double msRate() const
{
return static_cast<double>(rate_) / 1000.;
}
/// @return rate per micro seconds (= rate / 1000000)
inline double usRate() const
{
return static_cast<double>(rate_) / 1000000.;
}
/// @return rate per nano seconds (= rate / 1000000000)
inline double nsRate() const
{
return static_cast<double>(rate_) / 1000000000.;

View file

@ -79,7 +79,7 @@ public:
/// Authenticate with basic scheme
ErrorCode authenticateBasic(const std::string& credentials);
/// Authenticate with <user>:<password>
/// Authenticate with user:password
ErrorCode authenticatePlain(const std::string& user_password);
/// Authenticate with bearer scheme
// ErrorCode authenticateBearer(const std::string& token);
@ -88,7 +88,7 @@ public:
/// Authenticate with scheme ("basic" or "bearer") and auth param
ErrorCode authenticate(const std::string& scheme, const std::string& param);
/// @return JWS token for @p username and @p password
// @return JWS token for @p username and @p password
// ErrorOr<std::string> getToken(const std::string& username, const std::string& password) const;
/// @return if the authenticated user has permission to access @p ressource
bool hasPermission(const std::string& resource) const;

View file

@ -146,7 +146,7 @@ void ControlServer::onMessageReceived(std::shared_ptr<ControlSession> session, c
}
void ControlServer::onNewSession(shared_ptr<ControlSession> session)
void ControlServer::onNewSession(std::shared_ptr<ControlSession> session)
{
std::lock_guard<std::recursive_mutex> mlock(session_mutex_);
session->start();

View file

@ -25,6 +25,7 @@
#include "FLAC/stream_encoder.h"
// standard headers
#include <array>
#include <cstdio>
#include <cstdlib>
#include <cstring>

View file

@ -76,6 +76,7 @@ struct ServerSettings
/// c'tor
Authorization() = default;
/// Init with @p conf_roles and @p conf_users
void init(const std::vector<std::string>& conf_roles, const std::vector<std::string>& conf_users)
{
roles.clear();

View file

@ -87,8 +87,9 @@ public:
buffer_ = boost::asio::buffer(message_->data);
}
// Implement the ConstBufferSequence requirements.
/// const buffer.
using value_type = boost::asio::const_buffer;
/// const buffer iterator
using const_iterator = const boost::asio::const_buffer*;
/// begin iterator

View file

@ -35,11 +35,11 @@ namespace streamreader
/// Tage entry??
struct TageEntry
{
std::string code;
std::string type;
std::string data;
bool isBase64{false};
int length{0};
std::string code; ///< code
std::string type; ///< type
std::string data; ///< data
bool isBase64{false}; ///< is base64?
int length{0}; ///< length
};
/// Starts shairport-sync and reads PCM data from stdout

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2024 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -47,7 +47,7 @@ public:
void start() override;
void stop() override;
protected:
private:
void do_read();
void initAlsa();
void uninitAlsa();

View file

@ -45,7 +45,9 @@ public:
/// c'tor. Encoded PCM data is passed to the PipeListener
AsioStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, const ServerSettings& server_settings, const StreamUri& uri);
/// Start the stream reader, init the encoder and optionally the stream control
void start() override;
/// Stop the stream reader
void stop() override;
protected:

View file

@ -30,7 +30,9 @@ namespace detail
struct category : public std::error_category
{
public:
/// @return category name
const char* name() const noexcept override;
/// @return error message for @p value
std::string message(int value) const override;
};

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2024 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
Copyright (C) 2024 Marcus Weseloh <marcus@weseloh.cc>
This program is free software: you can redistribute it and/or modify
@ -49,7 +49,7 @@ public:
void start() override;
void stop() override;
protected:
private:
bool openJackConnection();
void closeJackConnection();
bool createJackPorts();

View file

@ -40,7 +40,7 @@ public:
/// ctor. Encoded PCM data is passed to the PipeListener
LibrespotStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, const ServerSettings& server_settings, const StreamUri& uri);
protected:
private:
bool killall_;
void onStderrMsg(const std::string& line) override;

View file

@ -114,13 +114,13 @@ public:
virtual void onStateChanged(const PcmStream* pcmStream, ReaderState state) = 0;
/// Chunk @p chunk of @p pcmStream has read
virtual void onChunkRead(const PcmStream* pcmStream, const msg::PcmChunk& chunk) = 0;
/// Chunk @p chunk with duration @p duration of stream @pcmStream has been encoded
/// Chunk @p chunk with duration @p duration of stream @p pcmStream has been encoded
virtual void onChunkEncoded(const PcmStream* pcmStream, std::shared_ptr<msg::PcmChunk> chunk, double duration) = 0;
/// Stream @p pcmStream muissed to read audio with duration @p ms
virtual void onResync(const PcmStream* pcmStream, double ms) = 0;
};
/// Handler function for command results
using ResultHandler = std::function<void(const snapcast::ErrorCode& ec)>;
/// c'tor. Encoded PCM data is passed to the PcmStream::Listener

View file

@ -42,29 +42,45 @@ namespace streamreader
{
/// Stream control base class
/// Controls a stream via "command" (play, pause, next, ...)
/// Provides status information (playback status, position, metadata, ...)
class StreamControl
{
public:
/// Request handler coming from the plugin
using OnRequest = std::function<void(const jsonrpcpp::Request& response)>;
/// Notification handler coming from the plugin
using OnNotification = std::function<void(const jsonrpcpp::Notification& response)>;
/// Response handler coming from the plugin
using OnResponse = std::function<void(const jsonrpcpp::Response& response)>;
/// Log handler coming from the plugin
using OnLog = std::function<void(std::string message)>;
/// c'tor
explicit StreamControl(const boost::asio::any_io_executor& executor);
/// d'tor
virtual ~StreamControl() = default;
/// Start the stream control, calls abstract "doStart"
void start(const std::string& stream_id, const ServerSettings& server_setttings, const OnNotification& notification_handler,
const OnRequest& request_handler, const OnLog& log_handler);
/// Issue a command to the stream, calls abstract "doCommand"
void command(const jsonrpcpp::Request& request, const OnResponse& response_handler);
protected:
/// abstract "command" interface: send a json request to the plugin
virtual void doCommand(const jsonrpcpp::Request& request) = 0;
/// abstract "start" interface: starts and initializes the plugin
virtual void doStart(const std::string& stream_id, const ServerSettings& server_setttings) = 0;
/// a @p json message has been received from the plugin
void onReceive(const std::string& json);
/// a @p message log request has been received from the plugin
void onLog(std::string message);
/// asio executor
boost::asio::any_io_executor executor_;
private:
@ -76,10 +92,14 @@ private:
};
/// Script based stream control
/// Executes a script (e.g. Python) and communicates via stdout/stdin with the script
class ScriptStreamControl : public StreamControl
{
public:
/// c'tor
ScriptStreamControl(const boost::asio::any_io_executor& executor, const std::filesystem::path& plugin_dir, std::string script, std::string params);
/// d'tor
virtual ~ScriptStreamControl() = default;
private:

View file

@ -1,6 +1,6 @@
/***
This file is part of snapcast
Copyright (C) 2014-2024 Johannes Pohl
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -39,10 +39,10 @@ namespace streamreader
class TcpStream : public AsioStream<tcp::socket>
{
public:
/// ctor. Encoded PCM data is passed to the PipeListener
/// c'tor. Encoded PCM data is passed to the PipeListener
TcpStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, const ServerSettings& server_settings, const StreamUri& uri);
protected:
private:
void connect() override;
void disconnect() override;
std::unique_ptr<tcp::acceptor> acceptor_;

View file

@ -36,10 +36,11 @@ class Watchdog;
class Watchdog
{
public:
/// Watchdog timeout handler
using TimeoutHandler = std::function<void(std::chrono::milliseconds ms)>;
/// c'tor
explicit Watchdog(const boost::asio::any_io_executor& executor);//, WatchdogListener* listener = nullptr);
explicit Watchdog(const boost::asio::any_io_executor& executor);
/// d'tor
virtual ~Watchdog();