mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-09 23:26:47 +02:00
Add namespace for encoder and decoder
This commit is contained in:
parent
c1a2fedd8d
commit
07e8290ee4
25 changed files with 124 additions and 38 deletions
|
@ -104,18 +104,18 @@ void Controller::onMessageReceived(ClientConnection* /*connection*/, const msg::
|
|||
player_.reset(nullptr);
|
||||
|
||||
if (headerChunk_->codec == "pcm")
|
||||
decoder_.reset(new PcmDecoder());
|
||||
decoder_ = make_unique<decoder::PcmDecoder>();
|
||||
#if defined(HAS_OGG) && (defined(HAS_TREMOR) || defined(HAS_VORBIS))
|
||||
else if (headerChunk_->codec == "ogg")
|
||||
decoder_.reset(new OggDecoder());
|
||||
decoder_ = make_unique<decoder::OggDecoder>();
|
||||
#endif
|
||||
#if defined(HAS_FLAC)
|
||||
else if (headerChunk_->codec == "flac")
|
||||
decoder_.reset(new FlacDecoder());
|
||||
decoder_ = make_unique<decoder::FlacDecoder>();
|
||||
#endif
|
||||
#if defined(HAS_OPUS)
|
||||
else if (headerChunk_->codec == "opus")
|
||||
decoder_.reset(new OpusDecoder());
|
||||
decoder_ = make_unique<decoder::OpusDecoder>();
|
||||
#endif
|
||||
else
|
||||
throw SnapException("codec not supported: \"" + headerChunk_->codec + "\"");
|
||||
|
@ -127,11 +127,11 @@ void Controller::onMessageReceived(ClientConnection* /*connection*/, const msg::
|
|||
stream_->setBufferLen(serverSettings_->getBufferMs() - latency_);
|
||||
|
||||
#ifdef HAS_ALSA
|
||||
player_.reset(new AlsaPlayer(pcmDevice_, stream_));
|
||||
player_ = make_unique<AlsaPlayer>(pcmDevice_, stream_);
|
||||
#elif HAS_OPENSL
|
||||
player_.reset(new OpenslPlayer(pcmDevice_, stream_));
|
||||
player_ = make_unique<OpenslPlayer>(pcmDevice_, stream_);
|
||||
#elif HAS_COREAUDIO
|
||||
player_.reset(new CoreAudioPlayer(pcmDevice_, stream_));
|
||||
player_ = make_unique<CoreAudioPlayer>(pcmDevice_, stream_);
|
||||
#else
|
||||
throw SnapException("No audio player support");
|
||||
#endif
|
||||
|
|
|
@ -73,7 +73,7 @@ private:
|
|||
int latency_;
|
||||
std::unique_ptr<ClientConnection> clientConnection_;
|
||||
std::shared_ptr<Stream> stream_;
|
||||
std::unique_ptr<Decoder> decoder_;
|
||||
std::unique_ptr<decoder::Decoder> decoder_;
|
||||
std::unique_ptr<Player> player_;
|
||||
std::shared_ptr<MetadataAdapter> meta_;
|
||||
std::shared_ptr<msg::ServerSettings> serverSettings_;
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "message/pcm_chunk.hpp"
|
||||
#include <mutex>
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
class Decoder
|
||||
{
|
||||
|
@ -37,5 +39,6 @@ protected:
|
|||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace decoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,20 +27,26 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data);
|
||||
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame, const FLAC__int32* const buffer[],
|
||||
void* client_data);
|
||||
static void metadata_callback(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata* metadata, void* client_data);
|
||||
static void error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data);
|
||||
|
||||
|
||||
static msg::CodecHeader* flacHeader = nullptr;
|
||||
static msg::PcmChunk* flacChunk = nullptr;
|
||||
static msg::PcmChunk* pcmChunk = nullptr;
|
||||
static SampleFormat sampleFormat;
|
||||
static FLAC__StreamDecoder* decoder = nullptr;
|
||||
namespace callback
|
||||
{
|
||||
FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data);
|
||||
FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame, const FLAC__int32* const buffer[],
|
||||
void* client_data);
|
||||
void metadata_callback(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata* metadata, void* client_data);
|
||||
void error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data);
|
||||
} // namespace callback
|
||||
|
||||
namespace
|
||||
{
|
||||
msg::CodecHeader* flacHeader = nullptr;
|
||||
msg::PcmChunk* flacChunk = nullptr;
|
||||
msg::PcmChunk* pcmChunk = nullptr;
|
||||
SampleFormat sampleFormat;
|
||||
FLAC__StreamDecoder* decoder = nullptr;
|
||||
} // namespace
|
||||
|
||||
|
||||
FlacDecoder::FlacDecoder() : Decoder(), lastError_(nullptr)
|
||||
|
@ -105,8 +111,8 @@ SampleFormat FlacDecoder::setHeader(msg::CodecHeader* chunk)
|
|||
throw SnapException("ERROR: allocating decoder");
|
||||
|
||||
// (void)FLAC__stream_decoder_set_md5_checking(decoder, true);
|
||||
init_status =
|
||||
FLAC__stream_decoder_init_stream(decoder, read_callback, nullptr, nullptr, nullptr, nullptr, write_callback, metadata_callback, error_callback, this);
|
||||
init_status = FLAC__stream_decoder_init_stream(decoder, callback::read_callback, nullptr, nullptr, nullptr, nullptr, callback::write_callback,
|
||||
callback::metadata_callback, callback::error_callback, this);
|
||||
if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
|
||||
throw SnapException("ERROR: initializing decoder: " + string(FLAC__StreamDecoderInitStatusString[init_status]));
|
||||
|
||||
|
@ -118,7 +124,8 @@ SampleFormat FlacDecoder::setHeader(msg::CodecHeader* chunk)
|
|||
return sampleFormat;
|
||||
}
|
||||
|
||||
|
||||
namespace callback
|
||||
{
|
||||
FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder* /*decoder*/, FLAC__byte buffer[], size_t* bytes, void* client_data)
|
||||
{
|
||||
if (flacHeader != nullptr)
|
||||
|
@ -213,3 +220,6 @@ void error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderError
|
|||
SLOG(ERROR) << "Got error callback: " << FLAC__StreamDecoderErrorStatusString[status] << "\n";
|
||||
static_cast<FlacDecoder*>(client_data)->lastError_ = std::unique_ptr<FLAC__StreamDecoderErrorStatus>(new FLAC__StreamDecoderErrorStatus(status));
|
||||
}
|
||||
} // namespace callback
|
||||
|
||||
} // namespace decoder
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
struct CacheInfo
|
||||
{
|
||||
|
@ -58,5 +59,6 @@ public:
|
|||
std::unique_ptr<FLAC__StreamDecoderErrorStatus> lastError_;
|
||||
};
|
||||
|
||||
} // namespace decoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
OggDecoder::OggDecoder() : Decoder()
|
||||
{
|
||||
|
@ -238,3 +240,5 @@ SampleFormat OggDecoder::setHeader(msg::CodecHeader* chunk)
|
|||
|
||||
return sampleFormat_;
|
||||
}
|
||||
|
||||
} // namespace decoder
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
#endif
|
||||
#include <ogg/ogg.h>
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
class OggDecoder : public Decoder
|
||||
{
|
||||
public:
|
||||
|
@ -59,5 +62,6 @@ private:
|
|||
SampleFormat sampleFormat_;
|
||||
};
|
||||
|
||||
} // namespace decoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "common/snap_exception.hpp"
|
||||
#include "common/str_compat.hpp"
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
#define ID_OPUS 0x4F505553
|
||||
|
||||
/// int: Number of samples per channel in the input signal.
|
||||
|
@ -108,3 +111,5 @@ SampleFormat OpusDecoder::setHeader(msg::CodecHeader* chunk)
|
|||
|
||||
return sample_format_;
|
||||
}
|
||||
|
||||
} // namespace decoder
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "decoder/decoder.hpp"
|
||||
#include <opus/opus.h>
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
class OpusDecoder : public Decoder
|
||||
{
|
||||
|
@ -31,7 +33,9 @@ public:
|
|||
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
||||
|
||||
private:
|
||||
OpusDecoder* dec_;
|
||||
::OpusDecoder* dec_;
|
||||
std::vector<opus_int16> pcm_;
|
||||
SampleFormat sample_format_;
|
||||
};
|
||||
|
||||
} // namespace decoder
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "common/endian.hpp"
|
||||
#include "common/snap_exception.hpp"
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
#define ID_RIFF 0x46464952
|
||||
#define ID_WAVE 0x45564157
|
||||
|
@ -118,3 +120,5 @@ SampleFormat PcmDecoder::setHeader(msg::CodecHeader* chunk)
|
|||
|
||||
return sampleFormat;
|
||||
}
|
||||
|
||||
} // namespace decoder
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "decoder.hpp"
|
||||
|
||||
|
||||
namespace decoder
|
||||
{
|
||||
|
||||
class PcmDecoder : public Decoder
|
||||
{
|
||||
public:
|
||||
|
@ -29,5 +32,6 @@ public:
|
|||
SampleFormat setHeader(msg::CodecHeader* chunk) override;
|
||||
};
|
||||
|
||||
} // namespace decoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "message/codec_header.hpp"
|
||||
#include "message/pcm_chunk.hpp"
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
class Encoder;
|
||||
|
||||
|
@ -96,5 +98,6 @@ protected:
|
|||
std::string codecOptions_;
|
||||
};
|
||||
|
||||
} // namespace encoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
Encoder* EncoderFactory::createEncoder(const std::string& codecSettings) const
|
||||
{
|
||||
|
@ -76,3 +78,5 @@ Encoder* EncoderFactory::createEncoder(const std::string& codecSettings) const
|
|||
}
|
||||
*/
|
||||
}
|
||||
|
||||
} // namespace encoder
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
#include "encoder.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
class EncoderFactory
|
||||
{
|
||||
public:
|
||||
|
@ -11,5 +14,6 @@ public:
|
|||
Encoder* createEncoder(const std::string& codecSettings) const;
|
||||
};
|
||||
|
||||
} // namespace encoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
FlacEncoder::FlacEncoder(const std::string& codecOptions) : Encoder(codecOptions), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0)
|
||||
{
|
||||
|
@ -133,14 +135,15 @@ FLAC__StreamEncoderWriteStatus FlacEncoder::write_callback(const FLAC__StreamEnc
|
|||
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
namespace callback
|
||||
{
|
||||
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples,
|
||||
unsigned current_frame, void* client_data)
|
||||
{
|
||||
FlacEncoder* flacEncoder = (FlacEncoder*)client_data;
|
||||
return flacEncoder->write_callback(encoder, buffer, bytes, samples, current_frame);
|
||||
}
|
||||
|
||||
} // namespace callback
|
||||
|
||||
void FlacEncoder::initEncoder()
|
||||
{
|
||||
|
@ -196,7 +199,9 @@ void FlacEncoder::initEncoder()
|
|||
throw SnapException("error setting meta data");
|
||||
|
||||
// initialize encoder
|
||||
init_status = FLAC__stream_encoder_init_stream(encoder_, ::write_callback, nullptr, nullptr, nullptr, this);
|
||||
init_status = FLAC__stream_encoder_init_stream(encoder_, callback::write_callback, nullptr, nullptr, nullptr, this);
|
||||
if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
|
||||
throw SnapException("ERROR: initializing encoder: " + string(FLAC__StreamEncoderInitStatusString[init_status]));
|
||||
}
|
||||
|
||||
} // namespace encoder
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "FLAC/metadata.h"
|
||||
#include "FLAC/stream_encoder.h"
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
class FlacEncoder : public Encoder
|
||||
{
|
||||
|
@ -53,5 +55,6 @@ protected:
|
|||
size_t encodedSamples_;
|
||||
};
|
||||
|
||||
} // namespace encoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
OggEncoder::OggEncoder(const std::string& codecOptions) : Encoder(codecOptions), lastGranulepos_(0)
|
||||
{
|
||||
|
@ -257,3 +259,5 @@ void OggEncoder::initEncoder()
|
|||
pos += og_.body_len;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace encoder
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include <ogg/ogg.h>
|
||||
#include <vorbis/vorbisenc.h>
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
class OggEncoder : public Encoder
|
||||
{
|
||||
public:
|
||||
|
@ -48,5 +51,6 @@ private:
|
|||
ogg_int64_t lastGranulepos_;
|
||||
};
|
||||
|
||||
} // namespace encoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include "common/str_compat.hpp"
|
||||
#include "common/utils/string_utils.hpp"
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
#define ID_OPUS 0x4F505553
|
||||
static constexpr opus_int32 const_min_bitrate = 6000;
|
||||
static constexpr opus_int32 const_max_bitrate = 512000;
|
||||
|
@ -36,8 +39,6 @@ void assign(void* pointer, T val)
|
|||
}
|
||||
} // namespace
|
||||
|
||||
// TODO:
|
||||
// - handle variable chunk durations (now it's fixed to 10ms)
|
||||
|
||||
OpusEncoder::OpusEncoder(const std::string& codecOptions) : Encoder(codecOptions), enc_(nullptr)
|
||||
{
|
||||
|
@ -152,6 +153,9 @@ void OpusEncoder::initEncoder()
|
|||
}
|
||||
|
||||
|
||||
// TODO:
|
||||
// handle variable chunk durations, now it's fixed to a "stream_buffer" value of
|
||||
// 5, 10, 20, 40, 60
|
||||
void OpusEncoder::encode(const msg::PcmChunk* chunk)
|
||||
{
|
||||
int samples_per_channel = chunk->getFrameCount();
|
||||
|
@ -179,3 +183,5 @@ void OpusEncoder::encode(const msg::PcmChunk* chunk)
|
|||
<< '\n';
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace encoder
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include <opus/opus.h>
|
||||
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
class OpusEncoder : public Encoder
|
||||
{
|
||||
public:
|
||||
|
@ -35,6 +38,8 @@ public:
|
|||
|
||||
protected:
|
||||
void initEncoder() override;
|
||||
OpusEncoder* enc_;
|
||||
::OpusEncoder* enc_;
|
||||
std::vector<u_char> encoded_;
|
||||
};
|
||||
|
||||
} // namespace encoder
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include <memory>
|
||||
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
#define ID_RIFF 0x46464952
|
||||
#define ID_WAVE 0x45564157
|
||||
#define ID_FMT 0x20746d66
|
||||
|
@ -76,3 +79,5 @@ std::string PcmEncoder::name() const
|
|||
{
|
||||
return "pcm";
|
||||
}
|
||||
|
||||
} // namespace encoder
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#define PCM_ENCODER_H
|
||||
#include "encoder.hpp"
|
||||
|
||||
namespace encoder
|
||||
{
|
||||
|
||||
class PcmEncoder : public Encoder
|
||||
{
|
||||
|
@ -32,5 +34,6 @@ protected:
|
|||
void initEncoder() override;
|
||||
};
|
||||
|
||||
} // namespace encoder
|
||||
|
||||
#endif
|
||||
|
|
|
@ -164,8 +164,8 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (settings.stream.codec.find(":?") != string::npos)
|
||||
{
|
||||
EncoderFactory encoderFactory;
|
||||
std::unique_ptr<Encoder> encoder(encoderFactory.createEncoder(settings.stream.codec));
|
||||
encoder::EncoderFactory encoderFactory;
|
||||
std::unique_ptr<encoder::Encoder> encoder(encoderFactory.createEncoder(settings.stream.codec));
|
||||
if (encoder)
|
||||
{
|
||||
cout << "Options for codec \"" << encoder->name() << "\":\n"
|
||||
|
|
|
@ -33,7 +33,7 @@ using namespace std;
|
|||
|
||||
PcmStream::PcmStream(PcmListener* pcmListener, const StreamUri& uri) : active_(false), pcmListener_(pcmListener), uri_(uri), pcmReadMs_(20), state_(kIdle)
|
||||
{
|
||||
EncoderFactory encoderFactory;
|
||||
encoder::EncoderFactory encoderFactory;
|
||||
if (uri_.query.find("codec") == uri_.query.end())
|
||||
throw SnapException("Stream URI must have a codec");
|
||||
encoder_.reset(encoderFactory.createEncoder(uri_.query["codec"]));
|
||||
|
@ -144,7 +144,7 @@ void PcmStream::setState(const ReaderState& newState)
|
|||
}
|
||||
|
||||
|
||||
void PcmStream::onChunkEncoded(const Encoder* /*encoder*/, msg::PcmChunk* chunk, double duration)
|
||||
void PcmStream::onChunkEncoded(const encoder::Encoder* /*encoder*/, msg::PcmChunk* chunk, double duration)
|
||||
{
|
||||
// LOG(INFO) << "onChunkEncoded: " << duration << " us\n";
|
||||
if (duration <= 0)
|
||||
|
|
|
@ -64,7 +64,7 @@ public:
|
|||
* Implements EncoderListener to get the encoded data.
|
||||
* Data is passed to the PcmListener
|
||||
*/
|
||||
class PcmStream : public EncoderListener
|
||||
class PcmStream : public encoder::EncoderListener
|
||||
{
|
||||
public:
|
||||
/// ctor. Encoded PCM data is passed to the PcmListener
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
virtual void stop();
|
||||
|
||||
/// Implementation of EncoderListener::onChunkEncoded
|
||||
void onChunkEncoded(const Encoder* encoder, msg::PcmChunk* chunk, double duration) override;
|
||||
void onChunkEncoded(const encoder::Encoder* encoder, msg::PcmChunk* chunk, double duration) override;
|
||||
virtual std::shared_ptr<msg::CodecHeader> getHeader();
|
||||
|
||||
virtual const StreamUri& getUri() const;
|
||||
|
@ -106,7 +106,7 @@ protected:
|
|||
SampleFormat sampleFormat_;
|
||||
size_t pcmReadMs_;
|
||||
size_t dryoutMs_;
|
||||
std::unique_ptr<Encoder> encoder_;
|
||||
std::unique_ptr<encoder::Encoder> encoder_;
|
||||
std::string name_;
|
||||
ReaderState state_;
|
||||
std::shared_ptr<msg::StreamTags> meta_;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue