encoder/Interface: pass std::span to Write() and Read()
This commit is contained in:
parent
28e044a36a
commit
7e14f8f830
@ -21,6 +21,7 @@
|
|||||||
#define MPD_ENCODER_INTERFACE_HXX
|
#define MPD_ENCODER_INTERFACE_HXX
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
struct AudioFormat;
|
struct AudioFormat;
|
||||||
struct Tag;
|
struct Tag;
|
||||||
@ -91,18 +92,19 @@ public:
|
|||||||
* @param data the buffer containing PCM samples
|
* @param data the buffer containing PCM samples
|
||||||
* @param length the length of the buffer in bytes
|
* @param length the length of the buffer in bytes
|
||||||
*/
|
*/
|
||||||
virtual void Write(const void *data, std::size_t length) = 0;
|
virtual void Write(std::span<const std::byte> src) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads encoded data from the encoder.
|
* Reads encoded data from the encoder.
|
||||||
*
|
*
|
||||||
* Call this repeatedly until no more data is returned.
|
* Call this repeatedly until no more data is returned.
|
||||||
*
|
*
|
||||||
* @param dest the destination buffer to copy to
|
* @param buffer a buffer that can be used to write data into
|
||||||
* @param length the maximum length of the destination buffer
|
*
|
||||||
* @return the number of bytes written to #dest
|
* @return the portion of the buffer that was filled (but may
|
||||||
|
* also point to a different buffer, e.g. one owned by this object)
|
||||||
*/
|
*/
|
||||||
virtual std::size_t Read(void *dest, std::size_t length) noexcept = 0;
|
virtual std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedEncoder {
|
class PreparedEncoder {
|
||||||
|
@ -28,12 +28,12 @@ EncoderToOutputStream(OutputStream &os, Encoder &encoder)
|
|||||||
/* read from the encoder */
|
/* read from the encoder */
|
||||||
|
|
||||||
std::byte buffer[32768];
|
std::byte buffer[32768];
|
||||||
size_t nbytes = encoder.Read(buffer, sizeof(buffer));
|
const auto r = encoder.Read(std::span{buffer});
|
||||||
if (nbytes == 0)
|
if (r.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* write everything to the stream */
|
/* write everything to the stream */
|
||||||
|
|
||||||
os.Write(buffer, nbytes);
|
os.Write(r.data(), r.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,10 @@ public:
|
|||||||
|
|
||||||
void SendTag(const Tag &tag) override;
|
void SendTag(const Tag &tag) override;
|
||||||
|
|
||||||
void Write(const void *data, size_t length) override;
|
void Write(std::span<const std::byte> src) override;
|
||||||
|
|
||||||
size_t Read(void *dest, size_t length) noexcept override {
|
std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept override {
|
||||||
return output_buffer.Read((std::byte *)dest, length);
|
return buffer.first(output_buffer.Read(buffer.data(), buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -267,27 +267,27 @@ pcm16_to_flac(int32_t *out, const int16_t *in, std::size_t num_samples) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FlacEncoder::Write(const void *data, size_t length)
|
FlacEncoder::Write(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
void *exbuffer;
|
void *exbuffer;
|
||||||
const void *buffer = nullptr;
|
const void *buffer = nullptr;
|
||||||
|
|
||||||
/* format conversion */
|
/* format conversion */
|
||||||
|
|
||||||
const std::size_t num_frames = length / audio_format.GetFrameSize();
|
const std::size_t num_frames = src.size() / audio_format.GetFrameSize();
|
||||||
const std::size_t num_samples = num_frames * audio_format.channels;
|
const std::size_t num_samples = num_frames * audio_format.channels;
|
||||||
|
|
||||||
switch (audio_format.format) {
|
switch (audio_format.format) {
|
||||||
case SampleFormat::S8:
|
case SampleFormat::S8:
|
||||||
exbuffer = expand_buffer.Get(length * 4);
|
exbuffer = expand_buffer.Get(src.size() * 4);
|
||||||
pcm8_to_flac((int32_t *)exbuffer, (const int8_t *)data,
|
pcm8_to_flac((int32_t *)exbuffer, (const int8_t *)src.data(),
|
||||||
num_samples);
|
num_samples);
|
||||||
buffer = exbuffer;
|
buffer = exbuffer;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
exbuffer = expand_buffer.Get(length * 2);
|
exbuffer = expand_buffer.Get(src.size() * 2);
|
||||||
pcm16_to_flac((int32_t *)exbuffer, (const int16_t *)data,
|
pcm16_to_flac((int32_t *)exbuffer, (const int16_t *)src.data(),
|
||||||
num_samples);
|
num_samples);
|
||||||
buffer = exbuffer;
|
buffer = exbuffer;
|
||||||
break;
|
break;
|
||||||
@ -296,7 +296,7 @@ FlacEncoder::Write(const void *data, size_t length)
|
|||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
/* nothing need to be done; format is the same for
|
/* nothing need to be done; format is the same for
|
||||||
both mpd and libFLAC */
|
both mpd and libFLAC */
|
||||||
buffer = data;
|
buffer = src.data();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "util/NumberParser.hxx"
|
#include "util/NumberParser.hxx"
|
||||||
#include "util/ReusableArray.hxx"
|
#include "util/ReusableArray.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
#include <lame/lame.h>
|
#include <lame/lame.h>
|
||||||
|
|
||||||
@ -167,14 +168,14 @@ LameEncoder::~LameEncoder() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LameEncoder::Write(std::span<const std::byte> src)
|
LameEncoder::Write(std::span<const std::byte> _src)
|
||||||
{
|
{
|
||||||
const auto *src = (const int16_t*)data;
|
const auto src = FromBytesStrict<const int16_t>(_src);
|
||||||
|
|
||||||
assert(output_begin == output_end);
|
assert(output_begin == output_end);
|
||||||
|
|
||||||
const std::size_t num_frames = length / audio_format.GetFrameSize();
|
const std::size_t num_samples = src.size();
|
||||||
const std::size_t num_samples = length / audio_format.GetSampleSize();
|
const std::size_t num_frames = num_samples / audio_format.channels;
|
||||||
|
|
||||||
/* worst-case formula according to LAME documentation */
|
/* worst-case formula according to LAME documentation */
|
||||||
const std::size_t output_buffer_size = 5 * num_samples / 4 + 7200;
|
const std::size_t output_buffer_size = 5 * num_samples / 4 + 7200;
|
||||||
@ -183,7 +184,7 @@ LameEncoder::Write(std::span<const std::byte> src)
|
|||||||
/* this is for only 16-bit audio */
|
/* this is for only 16-bit audio */
|
||||||
|
|
||||||
int bytes_out = lame_encode_buffer_interleaved(gfp,
|
int bytes_out = lame_encode_buffer_interleaved(gfp,
|
||||||
const_cast<short *>(src),
|
const_cast<short *>(src.data()),
|
||||||
num_frames,
|
num_frames,
|
||||||
dest, output_buffer_size);
|
dest, output_buffer_size);
|
||||||
|
|
||||||
@ -194,19 +195,18 @@ LameEncoder::Write(std::span<const std::byte> src)
|
|||||||
output_end = dest + bytes_out;
|
output_end = dest + bytes_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
std::span<const std::byte>
|
||||||
LameEncoder::Read(void *dest, size_t length) noexcept
|
LameEncoder::Read(std::span<std::byte> buffer) noexcept
|
||||||
{
|
{
|
||||||
const auto begin = output_begin;
|
const auto begin = output_begin;
|
||||||
assert(begin <= output_end);
|
assert(begin <= output_end);
|
||||||
const std::size_t remainning = output_end - begin;
|
const std::size_t remainning = output_end - begin;
|
||||||
if (length > remainning)
|
const std::size_t nbytes = std::min(remainning, buffer.size());
|
||||||
length = remainning;
|
|
||||||
|
|
||||||
memcpy(dest, begin, length);
|
memcpy(buffer.data(), begin, nbytes);
|
||||||
|
|
||||||
output_begin = begin + length;
|
output_begin = begin + nbytes;
|
||||||
return length;
|
return buffer.first(nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const EncoderPlugin lame_encoder_plugin = {
|
const EncoderPlugin lame_encoder_plugin = {
|
||||||
|
@ -29,12 +29,12 @@ public:
|
|||||||
:Encoder(false) {}
|
:Encoder(false) {}
|
||||||
|
|
||||||
/* virtual methods from class Encoder */
|
/* virtual methods from class Encoder */
|
||||||
void Write(const void *data, size_t length) override {
|
void Write(std::span<const std::byte> src) override {
|
||||||
buffer.Append({(const std::byte *)data, length});
|
buffer.Append(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *dest, size_t length) noexcept override {
|
std::span<const std::byte> Read(std::span<std::byte> b) noexcept override {
|
||||||
return buffer.Read((std::byte *)dest, length);
|
return b.first(buffer.Read(b.data(), b.size()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public:
|
|||||||
flush = true;
|
flush = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *dest, size_t length) noexcept override {
|
std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept override {
|
||||||
ogg_page page;
|
ogg_page page;
|
||||||
bool success = stream.PageOut(page);
|
bool success = stream.PageOut(page);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -60,10 +60,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
return 0;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReadPage(page, dest, length);
|
return buffer.first(ReadPage(page, buffer.data(),
|
||||||
|
buffer.size()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ public:
|
|||||||
|
|
||||||
/* virtual methods from class Encoder */
|
/* virtual methods from class Encoder */
|
||||||
void End() override;
|
void End() override;
|
||||||
void Write(const void *data, size_t length) override;
|
void Write(std::span<const std::byte> src) override;
|
||||||
|
|
||||||
void PreTag() override;
|
void PreTag() override;
|
||||||
void SendTag(const Tag &tag) override;
|
void SendTag(const Tag &tag) override;
|
||||||
@ -272,10 +272,8 @@ OpusEncoder::WriteSilence(unsigned fill_frames)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OpusEncoder::Write(const void *_data, size_t length)
|
OpusEncoder::Write(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
const auto *data = (const std::byte *)_data;
|
|
||||||
|
|
||||||
if (lookahead > 0) {
|
if (lookahead > 0) {
|
||||||
/* generate some silence at the beginning of the
|
/* generate some silence at the beginning of the
|
||||||
stream */
|
stream */
|
||||||
@ -286,14 +284,12 @@ OpusEncoder::Write(const void *_data, size_t length)
|
|||||||
lookahead = 0;
|
lookahead = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (length > 0) {
|
while (!src.empty()) {
|
||||||
size_t nbytes = buffer_size - buffer_position;
|
const std::size_t nbytes = std::min(buffer_size - buffer_position,
|
||||||
if (nbytes > length)
|
src.size());
|
||||||
nbytes = length;
|
|
||||||
|
|
||||||
memcpy(buffer + buffer_position, data, nbytes);
|
memcpy(buffer + buffer_position, src.data(), nbytes);
|
||||||
data += nbytes;
|
src = src.subspan(nbytes);
|
||||||
length -= nbytes;
|
|
||||||
buffer_position += nbytes;
|
buffer_position += nbytes;
|
||||||
|
|
||||||
if (buffer_position == buffer_size)
|
if (buffer_position == buffer_size)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "pcm/AudioFormat.hxx"
|
#include "pcm/AudioFormat.hxx"
|
||||||
#include "util/DynamicFifoBuffer.hxx"
|
#include "util/DynamicFifoBuffer.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -75,10 +76,10 @@ public:
|
|||||||
|
|
||||||
void Flush() override;
|
void Flush() override;
|
||||||
|
|
||||||
void Write(const void *data, size_t length) override;
|
void Write(std::span<const std::byte> src) override;
|
||||||
|
|
||||||
size_t Read(void *dest, size_t length) noexcept override {
|
std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept override {
|
||||||
return output_buffer.Read((std::byte *)dest, length);
|
return buffer.first(output_buffer.Read(buffer.data(), buffer.size()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -165,24 +166,24 @@ ShineEncoder::WriteChunk(bool flush)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ShineEncoder::Write(const void *_data, size_t length)
|
ShineEncoder::Write(std::span<const std::byte> _src)
|
||||||
{
|
{
|
||||||
const auto *data = (const int16_t*)_data;
|
const auto src = FromBytesStrict<const int16_t>(_src);
|
||||||
length /= sizeof(*data) * audio_format.channels;
|
const std::size_t nframes = src.size() / audio_format.channels;
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
|
|
||||||
if (input_pos > SHINE_MAX_SAMPLES)
|
if (input_pos > SHINE_MAX_SAMPLES)
|
||||||
input_pos = 0;
|
input_pos = 0;
|
||||||
|
|
||||||
/* write all data to de-interleaved buffers */
|
/* write all data to de-interleaved buffers */
|
||||||
while (written < length) {
|
while (written < nframes) {
|
||||||
for (;
|
for (;
|
||||||
written < length && input_pos < frame_size;
|
written < nframes && input_pos < frame_size;
|
||||||
written++, input_pos++) {
|
written++, input_pos++) {
|
||||||
const size_t base =
|
const size_t base =
|
||||||
written * audio_format.channels;
|
written * audio_format.channels;
|
||||||
stereo[0][input_pos] = data[base];
|
stereo[0][input_pos] = src[base];
|
||||||
stereo[1][input_pos] = data[base + 1];
|
stereo[1][input_pos] = src[base + 1];
|
||||||
}
|
}
|
||||||
/* write if chunk is filled */
|
/* write if chunk is filled */
|
||||||
WriteChunk(false);
|
WriteChunk(false);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "pcm/AudioFormat.hxx"
|
#include "pcm/AudioFormat.hxx"
|
||||||
#include "util/NumberParser.hxx"
|
#include "util/NumberParser.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
@ -67,8 +68,8 @@ public:
|
|||||||
flush = true;
|
flush = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(const void *data, size_t length) override;
|
void Write(std::span<const std::byte> src) override;
|
||||||
size_t Read(void *dest, size_t length) noexcept override;
|
std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreparedTwolameEncoder final : public PreparedEncoder {
|
class PreparedTwolameEncoder final : public PreparedEncoder {
|
||||||
@ -187,16 +188,16 @@ TwolameEncoder::~TwolameEncoder() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TwolameEncoder::Write(const void *data, size_t length)
|
TwolameEncoder::Write(std::span<const std::byte> _src)
|
||||||
{
|
{
|
||||||
const auto *src = (const int16_t*)data;
|
const auto src = FromBytesStrict<const int16_t>(_src);
|
||||||
|
|
||||||
assert(output_buffer_position == output_buffer_length);
|
assert(output_buffer_position == output_buffer_length);
|
||||||
|
|
||||||
const std::size_t num_frames = length / audio_format.GetFrameSize();
|
const std::size_t num_frames = src.size() / audio_format.channels;
|
||||||
|
|
||||||
int bytes_out = twolame_encode_buffer_interleaved(options,
|
int bytes_out = twolame_encode_buffer_interleaved(options,
|
||||||
src, num_frames,
|
src.data(), num_frames,
|
||||||
output_buffer,
|
output_buffer,
|
||||||
sizeof(output_buffer));
|
sizeof(output_buffer));
|
||||||
if (bytes_out < 0)
|
if (bytes_out < 0)
|
||||||
@ -206,8 +207,8 @@ TwolameEncoder::Write(const void *data, size_t length)
|
|||||||
output_buffer_position = 0;
|
output_buffer_position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
std::span<const std::byte>
|
||||||
TwolameEncoder::Read(void *dest, size_t length) noexcept
|
TwolameEncoder::Read(std::span<std::byte> buffer) noexcept
|
||||||
{
|
{
|
||||||
assert(output_buffer_position <= output_buffer_length);
|
assert(output_buffer_position <= output_buffer_length);
|
||||||
|
|
||||||
@ -224,14 +225,13 @@ TwolameEncoder::Read(void *dest, size_t length) noexcept
|
|||||||
|
|
||||||
|
|
||||||
const std::size_t remainning = output_buffer_length - output_buffer_position;
|
const std::size_t remainning = output_buffer_length - output_buffer_position;
|
||||||
if (length > remainning)
|
const std::size_t nbytes = std::min(remainning, buffer.size());
|
||||||
length = remainning;
|
|
||||||
|
|
||||||
memcpy(dest, output_buffer + output_buffer_position, length);
|
memcpy(buffer.data(), output_buffer + output_buffer_position, nbytes);
|
||||||
|
|
||||||
output_buffer_position += length;
|
output_buffer_position += nbytes;
|
||||||
|
|
||||||
return length;
|
return buffer.first(nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const EncoderPlugin twolame_encoder_plugin = {
|
const EncoderPlugin twolame_encoder_plugin = {
|
||||||
|
@ -55,7 +55,7 @@ public:
|
|||||||
void PreTag() override;
|
void PreTag() override;
|
||||||
void SendTag(const Tag &tag) override;
|
void SendTag(const Tag &tag) override;
|
||||||
|
|
||||||
void Write(const void *data, size_t length) override;
|
void Write(std::span<const std::byte> src) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HeaderOut(vorbis_comment &vc);
|
void HeaderOut(vorbis_comment &vc);
|
||||||
@ -245,14 +245,14 @@ interleaved_to_vorbis_buffer(float **dest, const float *src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VorbisEncoder::Write(const void *data, size_t length)
|
VorbisEncoder::Write(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
std::size_t num_frames = length / audio_format.GetFrameSize();
|
std::size_t num_frames = src.size() / audio_format.GetFrameSize();
|
||||||
|
|
||||||
/* this is for only 16-bit audio */
|
/* this is for only 16-bit audio */
|
||||||
|
|
||||||
interleaved_to_vorbis_buffer(vorbis_analysis_buffer(&vd, num_frames),
|
interleaved_to_vorbis_buffer(vorbis_analysis_buffer(&vd, num_frames),
|
||||||
(const float *)data,
|
(const float *)(const void *)src.data(),
|
||||||
num_frames,
|
num_frames,
|
||||||
audio_format.channels);
|
audio_format.channels);
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@ public:
|
|||||||
explicit WaveEncoder(AudioFormat &audio_format) noexcept;
|
explicit WaveEncoder(AudioFormat &audio_format) noexcept;
|
||||||
|
|
||||||
/* virtual methods from class Encoder */
|
/* virtual methods from class Encoder */
|
||||||
void Write(const void *data, size_t length) override;
|
void Write(std::span<const std::byte> src) override;
|
||||||
|
|
||||||
size_t Read(void *dest, size_t length) noexcept override {
|
std::span<const std::byte> Read(std::span<std::byte> b) noexcept override {
|
||||||
return buffer.Read((std::byte *)dest, length);
|
return b.first(buffer.Read(b.data(), b.size()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,8 +183,9 @@ pcm24_to_wave(uint8_t *dst8, const uint32_t *src32, size_t length) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WaveEncoder::Write(const void *src, size_t length)
|
WaveEncoder::Write(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
|
std::size_t length = src.size();
|
||||||
std::byte *dst = buffer.Write(length);
|
std::byte *dst = buffer.Write(length);
|
||||||
|
|
||||||
if (IsLittleEndian()) {
|
if (IsLittleEndian()) {
|
||||||
@ -192,29 +193,33 @@ WaveEncoder::Write(const void *src, size_t length)
|
|||||||
case 8:
|
case 8:
|
||||||
case 16:
|
case 16:
|
||||||
case 32:// optimized cases
|
case 32:// optimized cases
|
||||||
memcpy(dst, src, length);
|
memcpy(dst, src.data(), length);
|
||||||
break;
|
break;
|
||||||
case 24:
|
case 24:
|
||||||
length = pcm24_to_wave((uint8_t *)dst,
|
length = pcm24_to_wave((uint8_t *)dst,
|
||||||
(const uint32_t *)src, length);
|
(const uint32_t *)(const void *)src.data(),
|
||||||
|
length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (bits) {
|
switch (bits) {
|
||||||
case 8:
|
case 8:
|
||||||
memcpy(dst, src, length);
|
memcpy(dst, src.data(), length);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
length = pcm16_to_wave((uint16_t *)dst,
|
length = pcm16_to_wave((uint16_t *)dst,
|
||||||
(const uint16_t *)src, length);
|
(const uint16_t *)(const void *)src.data(),
|
||||||
|
length);
|
||||||
break;
|
break;
|
||||||
case 24:
|
case 24:
|
||||||
length = pcm24_to_wave((uint8_t *)dst,
|
length = pcm24_to_wave((uint8_t *)dst,
|
||||||
(const uint32_t *)src, length);
|
(const uint32_t *)(const void *)src.data(),
|
||||||
|
length);
|
||||||
break;
|
break;
|
||||||
case 32:
|
case 32:
|
||||||
length = pcm32_to_wave((uint32_t *)dst,
|
length = pcm32_to_wave((uint32_t *)dst,
|
||||||
(const uint32_t *)src, length);
|
(const uint32_t *)(const void *)src.data(),
|
||||||
|
length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ RecorderOutput::Play(const void *chunk, size_t size)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->Write(chunk, size);
|
encoder->Write({(const std::byte *)chunk, size});
|
||||||
|
|
||||||
EncoderToFile();
|
EncoderToFile();
|
||||||
|
|
||||||
|
@ -326,12 +326,14 @@ static void
|
|||||||
EncoderToShout(shout_t *shout_conn, Encoder &encoder)
|
EncoderToShout(shout_t *shout_conn, Encoder &encoder)
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
uint8_t buffer[32768];
|
std::byte buffer[32768];
|
||||||
size_t nbytes = encoder.Read(buffer, sizeof(buffer));
|
const auto e = encoder.Read(std::span{buffer});
|
||||||
if (nbytes == 0)
|
if (e.empty() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int err = shout_send(shout_conn, buffer, nbytes);
|
int err = shout_send(shout_conn,
|
||||||
|
(const unsigned char *)e.data(),
|
||||||
|
e.size());
|
||||||
HandleShoutError(shout_conn, err);
|
HandleShoutError(shout_conn, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,7 +416,7 @@ ShoutOutput::Delay() const noexcept
|
|||||||
size_t
|
size_t
|
||||||
ShoutOutput::Play(const void *chunk, size_t size)
|
ShoutOutput::Play(const void *chunk, size_t size)
|
||||||
{
|
{
|
||||||
encoder->Write(chunk, size);
|
encoder->Write({(const std::byte *)chunk, size});
|
||||||
WritePage();
|
WritePage();
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@ -422,9 +424,9 @@ ShoutOutput::Play(const void *chunk, size_t size)
|
|||||||
bool
|
bool
|
||||||
ShoutOutput::Pause()
|
ShoutOutput::Pause()
|
||||||
{
|
{
|
||||||
static char silence[1020];
|
static std::byte silence[1020];
|
||||||
|
|
||||||
encoder->Write(silence, sizeof(silence));
|
encoder->Write(std::span{silence});
|
||||||
WritePage();
|
WritePage();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
struct ConfigBlock;
|
struct ConfigBlock;
|
||||||
class EventLoop;
|
class EventLoop;
|
||||||
@ -249,7 +250,7 @@ public:
|
|||||||
*
|
*
|
||||||
* Throws on error.
|
* Throws on error.
|
||||||
*/
|
*/
|
||||||
void EncodeAndPlay(const void *chunk, size_t size);
|
void EncodeAndPlay(std::span<const std::byte> src);
|
||||||
|
|
||||||
void SendTag(const Tag &tag) override;
|
void SendTag(const Tag &tag) override;
|
||||||
|
|
||||||
|
@ -161,14 +161,13 @@ HttpdOutput::ReadPage() noexcept
|
|||||||
|
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
do {
|
do {
|
||||||
size_t nbytes = encoder->Read(buffer + size,
|
const auto r = encoder->Read(std::span{buffer}.subspan(size));
|
||||||
sizeof(buffer) - size);
|
if (r.empty())
|
||||||
if (nbytes == 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
unflushed_input = 0;
|
unflushed_input = 0;
|
||||||
|
|
||||||
size += nbytes;
|
size += r.size();
|
||||||
} while (size < sizeof(buffer));
|
} while (size < sizeof(buffer));
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
@ -301,11 +300,11 @@ HttpdOutput::BroadcastFromEncoder() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
HttpdOutput::EncodeAndPlay(const void *chunk, size_t size)
|
HttpdOutput::EncodeAndPlay(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
encoder->Write(chunk, size);
|
encoder->Write(src);
|
||||||
|
|
||||||
unflushed_input += size;
|
unflushed_input += src.size();
|
||||||
|
|
||||||
BroadcastFromEncoder();
|
BroadcastFromEncoder();
|
||||||
}
|
}
|
||||||
@ -316,7 +315,7 @@ HttpdOutput::Play(const void *chunk, size_t size)
|
|||||||
pause = false;
|
pause = false;
|
||||||
|
|
||||||
if (LockHasClients())
|
if (LockHasClients())
|
||||||
EncodeAndPlay(chunk, size);
|
EncodeAndPlay({(const std::byte *)chunk, size});
|
||||||
|
|
||||||
if (!timer->IsStarted())
|
if (!timer->IsStarted())
|
||||||
timer->Start();
|
timer->Start();
|
||||||
|
@ -128,9 +128,7 @@ ReadEncoder(Encoder &encoder) noexcept
|
|||||||
{
|
{
|
||||||
std::byte buffer[4096];
|
std::byte buffer[4096];
|
||||||
|
|
||||||
size_t nbytes = encoder.Read(buffer, sizeof(buffer));
|
return AllocatedArray<std::byte>{encoder.Read(std::span{buffer})};
|
||||||
const std::span<const std::byte> src{buffer, nbytes};
|
|
||||||
return AllocatedArray<std::byte>{src};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -313,7 +311,7 @@ SnapcastOutput::Play(const void *chunk, size_t size)
|
|||||||
if (!LockHasClients())
|
if (!LockHasClients())
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
encoder->Write(chunk, size);
|
encoder->Write({(const std::byte *)chunk, size});
|
||||||
unflushed_input += size;
|
unflushed_input += size;
|
||||||
|
|
||||||
if (unflushed_input >= 65536) {
|
if (unflushed_input >= 65536) {
|
||||||
@ -332,8 +330,8 @@ SnapcastOutput::Play(const void *chunk, size_t size)
|
|||||||
while (true) {
|
while (true) {
|
||||||
std::byte buffer[32768];
|
std::byte buffer[32768];
|
||||||
|
|
||||||
size_t nbytes = encoder->Read(buffer, sizeof(buffer));
|
const auto payload = encoder->Read(std::span{buffer});
|
||||||
if (nbytes == 0)
|
if (payload.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
unflushed_input = 0;
|
unflushed_input = 0;
|
||||||
@ -342,7 +340,6 @@ SnapcastOutput::Play(const void *chunk, size_t size)
|
|||||||
if (chunks.empty())
|
if (chunks.empty())
|
||||||
inject_event.Schedule();
|
inject_event.Schedule();
|
||||||
|
|
||||||
const std::span<const std::byte> payload{buffer, nbytes};
|
|
||||||
chunks.push(std::make_shared<SnapcastChunk>(now, AllocatedArray{payload}));
|
chunks.push(std::make_shared<SnapcastChunk>(now, AllocatedArray{payload}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
try {
|
try {
|
||||||
const char *encoder_name;
|
const char *encoder_name;
|
||||||
static char buffer[32768];
|
|
||||||
|
|
||||||
/* parse command line */
|
/* parse command line */
|
||||||
|
|
||||||
@ -79,9 +78,10 @@ try {
|
|||||||
|
|
||||||
/* do it */
|
/* do it */
|
||||||
|
|
||||||
|
static std::byte buffer[32768];
|
||||||
ssize_t nbytes;
|
ssize_t nbytes;
|
||||||
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
|
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
|
||||||
encoder->Write(buffer, nbytes);
|
encoder->Write(std::span{buffer}.first(nbytes));
|
||||||
EncoderToOutputStream(os, *encoder);
|
EncoderToOutputStream(os, *encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,6 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
static uint8_t zero[256];
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
|
main([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
|
||||||
try {
|
try {
|
||||||
@ -61,7 +59,8 @@ try {
|
|||||||
|
|
||||||
/* write a block of data */
|
/* write a block of data */
|
||||||
|
|
||||||
encoder->Write(zero, sizeof(zero));
|
static constexpr std::byte zero[256]{};
|
||||||
|
encoder->Write(std::span{zero});
|
||||||
|
|
||||||
EncoderToOutputStream(os, *encoder);
|
EncoderToOutputStream(os, *encoder);
|
||||||
|
|
||||||
@ -86,7 +85,7 @@ try {
|
|||||||
|
|
||||||
/* write another block of data */
|
/* write another block of data */
|
||||||
|
|
||||||
encoder->Write(zero, sizeof(zero));
|
encoder->Write(std::span{zero});
|
||||||
|
|
||||||
/* finish */
|
/* finish */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user