mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-31 01:46:16 +02:00
Add documentation
This commit is contained in:
parent
a692cc8874
commit
1460a530d8
25 changed files with 140 additions and 80 deletions
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -32,34 +32,38 @@
|
||||||
namespace decoder
|
namespace decoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// Cache internal decoder status
|
||||||
struct CacheInfo
|
struct CacheInfo
|
||||||
{
|
{
|
||||||
CacheInfo() : sampleRate_(0)
|
/// Reset current cache info
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
isCachedChunk_ = true;
|
isCachedChunk_ = true;
|
||||||
cachedBlocks_ = 0;
|
cachedBlocks_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCachedChunk_;
|
bool isCachedChunk_{true}; ///< is the current block cached
|
||||||
size_t cachedBlocks_;
|
size_t cachedBlocks_{0}; ///< number of cached blocks
|
||||||
size_t sampleRate_;
|
size_t sampleRate_{0}; ///< sample rate of the block
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Flac decoder
|
||||||
class FlacDecoder : public Decoder
|
class FlacDecoder : public Decoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// c'tor
|
||||||
FlacDecoder();
|
FlacDecoder();
|
||||||
|
/// d'tor
|
||||||
~FlacDecoder() override;
|
~FlacDecoder() override;
|
||||||
|
|
||||||
bool decode(msg::PcmChunk* chunk) override;
|
bool decode(msg::PcmChunk* chunk) override;
|
||||||
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
||||||
|
|
||||||
|
/// Flac internal cache info
|
||||||
CacheInfo cacheInfo_;
|
CacheInfo cacheInfo_;
|
||||||
|
/// Last decoder error
|
||||||
std::unique_ptr<FLAC__StreamDecoderErrorStatus> lastError_;
|
std::unique_ptr<FLAC__StreamDecoderErrorStatus> lastError_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,10 +25,13 @@
|
||||||
namespace decoder
|
namespace decoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Dummy decoder, doing actually nothing
|
||||||
class NullDecoder : public Decoder
|
class NullDecoder : public Decoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// c'tor
|
||||||
NullDecoder();
|
NullDecoder();
|
||||||
|
|
||||||
bool decode(msg::PcmChunk* chunk) override;
|
bool decode(msg::PcmChunk* chunk) override;
|
||||||
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
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
|
||||||
|
@ -36,11 +36,15 @@
|
||||||
namespace decoder
|
namespace decoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Ogg decoder
|
||||||
class OggDecoder : public Decoder
|
class OggDecoder : public Decoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// c'tor
|
||||||
OggDecoder();
|
OggDecoder();
|
||||||
|
/// d'tor
|
||||||
~OggDecoder() override;
|
~OggDecoder() override;
|
||||||
|
|
||||||
bool decode(msg::PcmChunk* chunk) override;
|
bool decode(msg::PcmChunk* chunk) override;
|
||||||
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
||||||
|
|
||||||
|
@ -57,15 +61,15 @@ private:
|
||||||
return static_cast<T>(value);
|
return static_cast<T>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ogg_sync_state oy; /// sync and verify incoming physical bitstream
|
ogg_sync_state oy; ///< sync and verify incoming physical bitstream
|
||||||
ogg_stream_state os; /// take physical pages, weld into a logical stream of packets
|
ogg_stream_state os; ///< take physical pages, weld into a logical stream of packets
|
||||||
ogg_page og; /// one Ogg bitstream page. Vorbis packets are inside
|
ogg_page og; ///< one Ogg bitstream page. Vorbis packets are inside
|
||||||
ogg_packet op; /// one raw packet of data for decode
|
ogg_packet op; ///< one raw packet of data for decode
|
||||||
|
|
||||||
vorbis_info vi; /// struct that stores all the static vorbis bitstream settings
|
vorbis_info vi; ///< struct that stores all the static vorbis bitstream settings
|
||||||
vorbis_comment vc; /// struct that stores all the bitstream user comments
|
vorbis_comment vc; ///< struct that stores all the bitstream user comments
|
||||||
vorbis_dsp_state vd; /// central working state for the packet->PCM decoder
|
vorbis_dsp_state vd; ///< central working state for the packet->PCM decoder
|
||||||
vorbis_block vb; /// local working space for packet->PCM decode
|
vorbis_block vb; ///< local working space for packet->PCM decode
|
||||||
|
|
||||||
SampleFormat sampleFormat_;
|
SampleFormat sampleFormat_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/***
|
/***
|
||||||
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-2024 Johannes Pohl
|
Copyright (C) 2016-2025 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
|
||||||
|
@ -36,11 +36,15 @@
|
||||||
namespace decoder
|
namespace decoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Opus decoder
|
||||||
class OpusDecoder : public Decoder
|
class OpusDecoder : public Decoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// c'tor
|
||||||
OpusDecoder();
|
OpusDecoder();
|
||||||
~OpusDecoder();
|
/// c'tor
|
||||||
|
~OpusDecoder() override;
|
||||||
|
|
||||||
bool decode(msg::PcmChunk* chunk) override;
|
bool decode(msg::PcmChunk* chunk) override;
|
||||||
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -32,14 +32,18 @@ static constexpr auto ID_WAVE = 0x45564157;
|
||||||
static constexpr auto ID_FMT = 0x20746d66;
|
static constexpr auto ID_FMT = 0x20746d66;
|
||||||
static constexpr auto ID_DATA = 0x61746164;
|
static constexpr auto ID_DATA = 0x61746164;
|
||||||
|
|
||||||
|
/// RIFF wave header
|
||||||
|
/// See https://en.wikipedia.org/wiki/WAV
|
||||||
struct riff_wave_header
|
struct riff_wave_header
|
||||||
{
|
{
|
||||||
uint32_t riff_id;
|
uint32_t riff_id; ///< "RIFF"
|
||||||
uint32_t riff_sz;
|
uint32_t riff_sz; ///< file size - 8
|
||||||
uint32_t wave_id;
|
uint32_t wave_id; ///< "WAVE"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Chunk header
|
||||||
|
/// See https://en.wikipedia.org/wiki/WAV
|
||||||
struct chunk_header
|
struct chunk_header
|
||||||
{
|
{
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
@ -47,9 +51,11 @@ struct chunk_header
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Chunk format
|
||||||
|
/// See https://en.wikipedia.org/wiki/WAV
|
||||||
struct chunk_fmt
|
struct chunk_fmt
|
||||||
{
|
{
|
||||||
uint16_t audio_format;
|
uint16_t audio_format; ///<
|
||||||
uint16_t num_channels;
|
uint16_t num_channels;
|
||||||
uint32_t sample_rate;
|
uint32_t sample_rate;
|
||||||
uint32_t byte_rate;
|
uint32_t byte_rate;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,10 +25,13 @@
|
||||||
namespace decoder
|
namespace decoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// PCM decoder
|
||||||
class PcmDecoder : public Decoder
|
class PcmDecoder : public Decoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// c'tor
|
||||||
PcmDecoder();
|
PcmDecoder();
|
||||||
|
|
||||||
bool decode(msg::PcmChunk* chunk) override;
|
bool decode(msg::PcmChunk* chunk) override;
|
||||||
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace player
|
||||||
|
|
||||||
static constexpr auto LOG_TAG = "WASAPI";
|
static constexpr auto LOG_TAG = "WASAPI";
|
||||||
|
|
||||||
|
/// COMMemDeleter helper
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct COMMemDeleter
|
struct COMMemDeleter
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
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,6 +33,7 @@
|
||||||
namespace player
|
namespace player
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Implementation of IAudioSessionEvents
|
||||||
class AudioSessionEventListener : public IAudioSessionEvents
|
class AudioSessionEventListener : public IAudioSessionEvents
|
||||||
{
|
{
|
||||||
LONG _cRef;
|
LONG _cRef;
|
||||||
|
@ -108,6 +109,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Implementation of IAudioEndpointVolumeCallback
|
||||||
class AudioEndpointVolumeCallback : public IAudioEndpointVolumeCallback
|
class AudioEndpointVolumeCallback : public IAudioEndpointVolumeCallback
|
||||||
{
|
{
|
||||||
LONG _cRef;
|
LONG _cRef;
|
||||||
|
@ -178,6 +180,7 @@ public:
|
||||||
|
|
||||||
static constexpr auto WASAPI = "wasapi";
|
static constexpr auto WASAPI = "wasapi";
|
||||||
|
|
||||||
|
/// WASAPI player
|
||||||
class WASAPIPlayer : public Player
|
class WASAPIPlayer : public Player
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -22,28 +22,33 @@
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// text_exception uses a dynamically-allocated internal c-string for what():
|
/// Snapcast specific exceptions
|
||||||
class SnapException : public std::exception
|
class SnapException : public std::exception
|
||||||
{
|
{
|
||||||
std::string text_;
|
std::string text_;
|
||||||
int error_code_;
|
int error_code_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// c'tor
|
||||||
explicit SnapException(const char* text, int error_code = 0) : text_(text), error_code_(error_code)
|
explicit SnapException(const char* text, int error_code = 0) : text_(text), error_code_(error_code)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// c'tor
|
||||||
explicit SnapException(const std::string& text, int error_code = 0) : SnapException(text.c_str(), error_code)
|
explicit SnapException(const std::string& text, int error_code = 0) : SnapException(text.c_str(), error_code)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// d'tor
|
||||||
~SnapException() override = default;
|
~SnapException() override = default;
|
||||||
|
|
||||||
|
/// @return error code
|
||||||
int code() const noexcept
|
int code() const noexcept
|
||||||
{
|
{
|
||||||
return error_code_;
|
return error_code_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @return the exception text
|
||||||
const char* what() const noexcept override
|
const char* what() const noexcept override
|
||||||
{
|
{
|
||||||
return text_.c_str();
|
return text_.c_str();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
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
|
||||||
|
@ -45,7 +45,7 @@ public:
|
||||||
|
|
||||||
/// c'tor
|
/// c'tor
|
||||||
/// Codec options (E.g. compression level) are passed as string and are codec dependend
|
/// Codec options (E.g. compression level) are passed as string and are codec dependend
|
||||||
Encoder(const std::string& codecOptions = "") : headerChunk_(nullptr), codecOptions_(codecOptions)
|
explicit Encoder(std::string codecOptions = "") : headerChunk_(nullptr), codecOptions_(std::move(codecOptions))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
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
|
||||||
|
@ -40,9 +40,9 @@ using namespace std;
|
||||||
namespace encoder
|
namespace encoder
|
||||||
{
|
{
|
||||||
|
|
||||||
std::unique_ptr<Encoder> EncoderFactory::createEncoder(const std::string& codecSettings) const
|
std::unique_ptr<Encoder> EncoderFactory::createEncoder(const std::string& codec_settings) const
|
||||||
{
|
{
|
||||||
std::string codec(codecSettings);
|
std::string codec(codec_settings);
|
||||||
std::string codecOptions;
|
std::string codecOptions;
|
||||||
if (codec.find(':') != std::string::npos)
|
if (codec.find(':') != std::string::npos)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
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
|
||||||
|
@ -29,11 +29,12 @@
|
||||||
namespace encoder
|
namespace encoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Factory to create an encoder from an URI
|
||||||
class EncoderFactory
|
class EncoderFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// EncoderFactory(const std::string& codecSettings);
|
/// @return Encoder from @p codec_settings
|
||||||
std::unique_ptr<Encoder> createEncoder(const std::string& codecSettings) const;
|
std::unique_ptr<Encoder> createEncoder(const std::string& codec_settings) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace encoder
|
} // namespace encoder
|
||||||
|
|
|
@ -40,7 +40,8 @@ namespace encoder
|
||||||
|
|
||||||
static constexpr auto LOG_TAG = "FlacEnc";
|
static constexpr auto LOG_TAG = "FlacEnc";
|
||||||
|
|
||||||
FlacEncoder::FlacEncoder(const std::string& codecOptions) : Encoder(codecOptions), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0), flacChunk_(nullptr)
|
FlacEncoder::FlacEncoder(std::string codecOptions)
|
||||||
|
: Encoder(std::move(codecOptions)), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0), flacChunk_(nullptr)
|
||||||
{
|
{
|
||||||
headerChunk_ = std::make_shared<msg::CodecHeader>("flac");
|
headerChunk_ = std::make_shared<msg::CodecHeader>("flac");
|
||||||
pcmBuffer_ = static_cast<FLAC__int32*>(malloc(pcmBufferSize_ * sizeof(FLAC__int32)));
|
pcmBuffer_ = static_cast<FLAC__int32*>(malloc(pcmBufferSize_ * sizeof(FLAC__int32)));
|
||||||
|
@ -230,7 +231,7 @@ void FlacEncoder::initEncoder()
|
||||||
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_.data(), 2);
|
||||||
if (ok == 0)
|
if (ok == 0)
|
||||||
throw SnapException("error setting meta data");
|
throw SnapException("error setting meta data");
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -32,24 +32,29 @@
|
||||||
namespace encoder
|
namespace encoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Flac encoder
|
||||||
class FlacEncoder : public Encoder
|
class FlacEncoder : public Encoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit FlacEncoder(const std::string& codecOptions = "");
|
/// c'tor
|
||||||
|
explicit FlacEncoder(std::string codecOptions);
|
||||||
|
/// d'tor
|
||||||
~FlacEncoder() override;
|
~FlacEncoder() override;
|
||||||
|
|
||||||
void encode(const msg::PcmChunk& chunk) override;
|
void encode(const msg::PcmChunk& chunk) override;
|
||||||
std::string getAvailableOptions() const override;
|
std::string getAvailableOptions() const override;
|
||||||
std::string getDefaultOptions() const override;
|
std::string getDefaultOptions() const override;
|
||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
|
|
||||||
|
/// FLAC write 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);
|
unsigned current_frame);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
void initEncoder() override;
|
void initEncoder() override;
|
||||||
|
|
||||||
FLAC__StreamEncoder* encoder_;
|
FLAC__StreamEncoder* encoder_;
|
||||||
FLAC__StreamMetadata* metadata_[2];
|
std::array<FLAC__StreamMetadata*, 2> metadata_;
|
||||||
|
|
||||||
FLAC__int32* pcmBuffer_;
|
FLAC__int32* pcmBuffer_;
|
||||||
int pcmBufferSize_;
|
int pcmBufferSize_;
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace encoder
|
||||||
|
|
||||||
static constexpr auto LOG_TAG = "NullEnc";
|
static constexpr auto LOG_TAG = "NullEnc";
|
||||||
|
|
||||||
NullEncoder::NullEncoder(const std::string& codecOptions) : Encoder(codecOptions)
|
NullEncoder::NullEncoder(std::string codecOptions) : Encoder(std::move(codecOptions))
|
||||||
{
|
{
|
||||||
headerChunk_ = std::make_shared<msg::CodecHeader>("null");
|
headerChunk_ = std::make_shared<msg::CodecHeader>("null");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -37,11 +37,13 @@ namespace encoder
|
||||||
class NullEncoder : public Encoder
|
class NullEncoder : public Encoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NullEncoder(const std::string& codecOptions = "");
|
/// c'tor
|
||||||
|
explicit NullEncoder(std::string codecOptions);
|
||||||
|
|
||||||
void encode(const msg::PcmChunk& chunk) override;
|
void encode(const msg::PcmChunk& chunk) override;
|
||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
void initEncoder() override;
|
void initEncoder() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,8 @@ namespace encoder
|
||||||
|
|
||||||
static constexpr auto LOG_TAG = "OggEnc";
|
static constexpr auto LOG_TAG = "OggEnc";
|
||||||
|
|
||||||
OggEncoder::OggEncoder(const std::string& codecOptions) : Encoder(codecOptions), lastGranulepos_(0)
|
|
||||||
|
OggEncoder::OggEncoder(std::string codecOptions) : Encoder(std::move(codecOptions)), lastGranulepos_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
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
|
||||||
|
@ -29,10 +29,13 @@
|
||||||
namespace encoder
|
namespace encoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Ogg encoder
|
||||||
class OggEncoder : public Encoder
|
class OggEncoder : public Encoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OggEncoder(const std::string& codecOptions = "");
|
/// c'tor
|
||||||
|
explicit OggEncoder(std::string codecOptions);
|
||||||
|
/// d'tor
|
||||||
~OggEncoder() override;
|
~OggEncoder() override;
|
||||||
|
|
||||||
void encode(const msg::PcmChunk& chunk) override;
|
void encode(const msg::PcmChunk& chunk) override;
|
||||||
|
@ -40,19 +43,18 @@ public:
|
||||||
std::string getDefaultOptions() const override;
|
std::string getDefaultOptions() const override;
|
||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
void initEncoder() override;
|
void initEncoder() override;
|
||||||
|
|
||||||
private:
|
ogg_stream_state os_; ///< take physical pages, weld into a logical stream of packets
|
||||||
ogg_stream_state os_; /// take physical pages, weld into a logical stream of packets
|
ogg_page og_; ///< one Ogg bitstream page. Vorbis packets are inside
|
||||||
ogg_page og_; /// one Ogg bitstream page. Vorbis packets are inside
|
ogg_packet op_; ///< one raw packet of data for decode
|
||||||
ogg_packet op_; /// one raw packet of data for decode
|
|
||||||
|
|
||||||
vorbis_info vi_; /// struct that stores all the static vorbis bitstream settings
|
vorbis_info vi_; ///< struct that stores all the static vorbis bitstream settings
|
||||||
vorbis_comment vc_; /// struct that stores all the user comments
|
vorbis_comment vc_; ///< struct that stores all the user comments
|
||||||
|
|
||||||
vorbis_dsp_state vd_; /// central working state for the packet->PCM decoder
|
vorbis_dsp_state vd_; ///< central working state for the packet->PCM decoder
|
||||||
vorbis_block vb_; /// local working space for packet->PCM decode
|
vorbis_block vb_; ///< local working space for packet->PCM decode
|
||||||
|
|
||||||
ogg_int64_t lastGranulepos_;
|
ogg_int64_t lastGranulepos_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,7 +50,7 @@ void assign(void* pointer, T val)
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
OpusEncoder::OpusEncoder(const std::string& codecOptions) : Encoder(codecOptions), enc_(nullptr), remainder_max_size_(0)
|
OpusEncoder::OpusEncoder(std::string codecOptions) : Encoder(std::move(codecOptions)), enc_(nullptr), remainder_max_size_(0)
|
||||||
{
|
{
|
||||||
headerChunk_ = make_unique<msg::CodecHeader>("opus");
|
headerChunk_ = make_unique<msg::CodecHeader>("opus");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/***
|
/***
|
||||||
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-2024 Johannes Pohl
|
Copyright (C) 2016-2025 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
|
||||||
|
@ -34,10 +34,13 @@
|
||||||
namespace encoder
|
namespace encoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Opuse encoder
|
||||||
class OpusEncoder : public Encoder
|
class OpusEncoder : public Encoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpusEncoder(const std::string& codecOptions = "");
|
/// c'tor
|
||||||
|
explicit OpusEncoder(std::string codecOptions);
|
||||||
|
/// d'tor
|
||||||
~OpusEncoder() override;
|
~OpusEncoder() override;
|
||||||
|
|
||||||
void encode(const msg::PcmChunk& chunk) override;
|
void encode(const msg::PcmChunk& chunk) override;
|
||||||
|
@ -45,7 +48,7 @@ public:
|
||||||
std::string getDefaultOptions() const override;
|
std::string getDefaultOptions() const override;
|
||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
void encode(const SampleFormat& format, const char* data, size_t size);
|
void encode(const SampleFormat& format, const char* data, size_t size);
|
||||||
void initEncoder() override;
|
void initEncoder() override;
|
||||||
::OpusEncoder* enc_;
|
::OpusEncoder* enc_;
|
||||||
|
|
|
@ -48,7 +48,7 @@ void assign(void* pointer, T val)
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
PcmEncoder::PcmEncoder(const std::string& codecOptions) : Encoder(codecOptions)
|
PcmEncoder::PcmEncoder(std::string codecOptions) : Encoder(std::move(codecOptions))
|
||||||
{
|
{
|
||||||
headerChunk_ = std::make_shared<msg::CodecHeader>("pcm");
|
headerChunk_ = std::make_shared<msg::CodecHeader>("pcm");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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-2025 Johannes Pohl
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,14 +25,17 @@
|
||||||
namespace encoder
|
namespace encoder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// PCM encoder
|
||||||
class PcmEncoder : public Encoder
|
class PcmEncoder : public Encoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PcmEncoder(const std::string& codecOptions = "");
|
/// c'tor
|
||||||
|
explicit PcmEncoder(std::string codecOptions);
|
||||||
|
|
||||||
void encode(const msg::PcmChunk& chunk) override;
|
void encode(const msg::PcmChunk& chunk) override;
|
||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
void initEncoder() override;
|
void initEncoder() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -32,18 +32,14 @@
|
||||||
namespace streamreader
|
namespace streamreader
|
||||||
{
|
{
|
||||||
|
|
||||||
class TageEntry
|
/// Tage entry??
|
||||||
|
struct TageEntry
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
TageEntry() : isBase64(false), length(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string code;
|
std::string code;
|
||||||
std::string type;
|
std::string type;
|
||||||
std::string data;
|
std::string data;
|
||||||
bool isBase64;
|
bool isBase64{false};
|
||||||
int length;
|
int length{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Starts shairport-sync and reads PCM data from stdout
|
/// Starts shairport-sync and reads PCM data from stdout
|
||||||
|
@ -58,11 +54,12 @@ public:
|
||||||
class AirplayStream : public ProcessStream
|
class AirplayStream : public ProcessStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// ctor. Encoded PCM data is passed to the PipeListener
|
/// c'tor. Encoded PCM data is passed to the PipeListener
|
||||||
AirplayStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, const ServerSettings& server_settings, const StreamUri& uri);
|
AirplayStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, const ServerSettings& server_settings, const StreamUri& uri);
|
||||||
|
/// d'tor
|
||||||
~AirplayStream() override;
|
~AirplayStream() override;
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
#ifdef HAS_EXPAT
|
#ifdef HAS_EXPAT
|
||||||
XML_Parser parser_;
|
XML_Parser parser_;
|
||||||
std::unique_ptr<TageEntry> entry_;
|
std::unique_ptr<TageEntry> entry_;
|
||||||
|
|
|
@ -37,21 +37,26 @@ namespace streamreader
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
/// Boost asio based stream class interface
|
||||||
template <typename ReadStream>
|
template <typename ReadStream>
|
||||||
class AsioStream : public PcmStream
|
class AsioStream : public PcmStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// ctor. Encoded PCM data is passed to the PipeListener
|
/// 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);
|
AsioStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, const ServerSettings& server_settings, const StreamUri& uri);
|
||||||
|
|
||||||
void start() override;
|
void start() override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// connect to the stream
|
||||||
virtual void connect() = 0;
|
virtual void connect() = 0;
|
||||||
|
/// disconnect from the stream
|
||||||
virtual void disconnect();
|
virtual void disconnect();
|
||||||
|
|
||||||
|
/// resets first chunk timer and starts reader loop
|
||||||
virtual void on_connect();
|
virtual void on_connect();
|
||||||
|
/// read from asio stream
|
||||||
virtual void do_read();
|
virtual void do_read();
|
||||||
/// Start a timer that will change the stream state to idle after \p duration
|
/// Start a timer that will change the stream state to idle after \p duration
|
||||||
void check_state(const std::chrono::steady_clock::duration& duration);
|
void check_state(const std::chrono::steady_clock::duration& duration);
|
||||||
|
@ -62,12 +67,18 @@ protected:
|
||||||
|
|
||||||
/// Cache last exception to avoid repeated error logging
|
/// Cache last exception to avoid repeated error logging
|
||||||
std::string lastException_;
|
std::string lastException_;
|
||||||
timeval tv_chunk_;
|
/// Marker: next chunk is the first chunk
|
||||||
bool first_;
|
bool first_;
|
||||||
|
|
||||||
|
/// next read = current chunk start + chunk duration
|
||||||
std::chrono::time_point<std::chrono::steady_clock> nextTick_;
|
std::chrono::time_point<std::chrono::steady_clock> nextTick_;
|
||||||
|
/// chunk read buffer
|
||||||
uint32_t buffer_ms_;
|
uint32_t buffer_ms_;
|
||||||
|
/// read timer
|
||||||
boost::asio::steady_timer read_timer_;
|
boost::asio::steady_timer read_timer_;
|
||||||
|
/// state timer: set stream to idle/playing on timeout
|
||||||
boost::asio::steady_timer state_timer_;
|
boost::asio::steady_timer state_timer_;
|
||||||
|
/// the stream
|
||||||
std::unique_ptr<ReadStream> stream_;
|
std::unique_ptr<ReadStream> stream_;
|
||||||
|
|
||||||
/// duration of the current silence period
|
/// duration of the current silence period
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace snapcast::error::control
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// control error category
|
||||||
struct category : public std::error_category
|
struct category : public std::error_category
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue