output/Interface: pass std::span to Play()

This commit is contained in:
Max Kellermann 2022-07-12 12:31:35 +02:00
parent f5d104e7af
commit 45071607aa
29 changed files with 138 additions and 141 deletions

View File

@ -173,10 +173,10 @@ FilteredAudioOutput::SendTag(const Tag &tag)
output->SendTag(tag);
}
size_t
FilteredAudioOutput::Play(const void *data, size_t size)
std::size_t
FilteredAudioOutput::Play(std::span<const std::byte> src)
{
return output->Play(data, size);
return output->Play(src);
}
void

View File

@ -23,10 +23,11 @@
#include "pcm/AudioFormat.hxx"
#include "filter/Observer.hxx"
#include <memory>
#include <string>
#include <map>
#include <chrono>
#include <map>
#include <memory>
#include <span>
#include <string>
class FilterFactory;
class PreparedFilter;
@ -224,7 +225,7 @@ public:
void SendTag(const Tag &tag);
size_t Play(const void *data, size_t size);
std::size_t Play(std::span<const std::byte> src);
void Drain();
void Cancel() noexcept;

View File

@ -21,8 +21,9 @@
#define MPD_AUDIO_OUTPUT_INTERFACE_HXX
#include <map>
#include <string>
#include <chrono>
#include <span>
#include <string>
struct AudioFormat;
struct Tag;
@ -180,7 +181,7 @@ public:
* @return the number of bytes played (must be a multiple of
* the frame size)
*/
virtual size_t Play(const void *chunk, size_t size) = 0;
virtual std::size_t Play(std::span<const std::byte> src) = 0;
/**
* Wait until the device has finished playing.

View File

@ -265,7 +265,7 @@ AudioOutputControl::PlayChunk(std::unique_lock<Mutex> &lock) noexcept
try {
const ScopeUnlock unlock(mutex);
nbytes = output->Play(data.data(), data.size());
nbytes = output->Play(data);
assert(nbytes > 0);
assert(nbytes <= data.size());
} catch (AudioOutputInterrupted) {
@ -380,7 +380,7 @@ static void
PlayFull(FilteredAudioOutput &output, std::span<const std::byte> buffer)
{
while (!buffer.empty()) {
size_t nbytes = output.Play(buffer.data(), buffer.size());
size_t nbytes = output.Play(buffer);
assert(nbytes > 0);
buffer = buffer.subspan(nbytes);

View File

@ -283,7 +283,7 @@ private:
void Interrupt() noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Drain() override;
void Cancel() noexcept override;
bool Pause() noexcept override;
@ -1219,26 +1219,26 @@ AlsaOutput::LockWaitWriteAvailable()
}
}
size_t
AlsaOutput::Play(const void *chunk, size_t size)
std::size_t
AlsaOutput::Play(std::span<const std::byte> src)
{
assert(size > 0);
assert(size % in_frame_size == 0);
assert(!src.empty());
assert(src.size() % in_frame_size == 0);
const size_t max_frames = LockWaitWriteAvailable();
const size_t max_size = max_frames * in_frame_size;
if (size > max_size)
size = max_size;
if (src.size() > max_size)
src = src.first(max_size);
const auto e = pcm_export->Export({(const std::byte *)chunk, size});
const auto e = pcm_export->Export(src);
if (e.empty())
return size;
return src.size();
size_t bytes_written = ring_buffer->push(e.data(), e.size());
assert(bytes_written == e.size());
(void)bytes_written;
return size;
return src.size();
}
Event::Duration

View File

@ -74,7 +74,7 @@ public:
void Open(AudioFormat &audio_format) override;
void Close() noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
};
static constexpr Domain ao_output_domain("ao_output");
@ -195,23 +195,24 @@ AoOutput::Close() noexcept
ao_close(device);
}
size_t
AoOutput::Play(const void *chunk, size_t size)
std::size_t
AoOutput::Play(std::span<const std::byte> src)
{
assert(size % frame_size == 0);
assert(src.size() % frame_size == 0);
if (size > max_size)
size = max_size;
if (src.size() > max_size)
/* round down to a multiple of the frame size */
src = src.first(max_size);
/* For whatever reason, libao wants a non-const pointer.
Let's hope it does not write to the buffer, and use the
union deconst hack to * work around this API misdesign. */
char *data = const_cast<char *>((const char *)chunk);
char *data = const_cast<char *>((const char *)src.data());
if (ao_play(device, data, size) == 0)
if (ao_play(device, data, src.size()) == 0)
throw MakeAoError();
return size;
return src.size();
}
const struct AudioOutputPlugin ao_output_plugin = {

View File

@ -69,7 +69,7 @@ private:
void Close() noexcept override;
[[nodiscard]] std::chrono::steady_clock::duration Delay() const noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Cancel() noexcept override;
};
@ -208,17 +208,17 @@ FifoOutput::Delay() const noexcept
: std::chrono::steady_clock::duration::zero();
}
size_t
FifoOutput::Play(const void *chunk, size_t size)
std::size_t
FifoOutput::Play(std::span<const std::byte> src)
{
if (!timer->IsStarted())
timer->Start();
timer->Add(size);
timer->Add(src.size());
while (true) {
ssize_t bytes = write(output, chunk, size);
ssize_t bytes = write(output, src.data(), src.size());
if (bytes > 0)
return (size_t)bytes;
return (std::size_t)bytes;
if (bytes < 0) {
switch (errno) {

View File

@ -75,7 +75,7 @@ private:
void Open(AudioFormat &audio_format) override;
void Close() noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
std::chrono::steady_clock::duration Delay() const noexcept override;
@ -256,17 +256,17 @@ HaikuOutput::Open(AudioFormat &audio_format)
sound_player->SetHasData(false);
}
size_t
HaikuOutput::Play(const void *chunk, size_t size)
std::size_t
HaikuOutput::Play(std::span<const std::byte> src)
{
BSoundPlayer* const soundPlayer = sound_player;
const uint8 *data = (const uint8 *)chunk;
const uint8 *data = (const uint8 *)src.data();
if (!soundPlayer->HasData())
soundPlayer->SetHasData(true);
acquire_sem(new_buffer);
size_t bytesLeft = size;
size_t bytesLeft = src.size();
while (bytesLeft > 0) {
if (buffer_filled == buffer_size) {
// Request another buffer from BSoundPlayer
@ -293,7 +293,7 @@ HaikuOutput::Play(const void *chunk, size_t size)
//soundPlayer->SetHasData(false);
}
return size;
return src.size();
}
inline std::chrono::steady_clock::duration

View File

@ -26,6 +26,7 @@
#include "util/ScopeExit.hxx"
#include "util/IterableSplitString.hxx"
#include "util/RuntimeError.hxx"
#include "util/SpanCast.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
@ -178,7 +179,7 @@ public:
: std::chrono::steady_clock::duration::zero();
}
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Cancel() noexcept override;
bool Pause() override;
@ -689,14 +690,17 @@ JackOutput::WriteSamples(const float *src, size_t n_frames)
return result;
}
inline size_t
JackOutput::Play(const void *chunk, size_t size)
std::size_t
JackOutput::Play(std::span<const std::byte> _src)
{
const auto src = FromBytesStrict<const float>(_src);
pause = false;
const size_t frame_size = audio_format.GetFrameSize();
assert(size % frame_size == 0);
size /= frame_size;
assert(src.size() % frame_size == 0);
const std::size_t n_frames = src.size() / audio_format.channels;
while (true) {
{
@ -709,7 +713,7 @@ JackOutput::Play(const void *chunk, size_t size)
}
size_t frames_written =
WriteSamples((const float *)chunk, size);
WriteSamples(src.data(), n_frames);
if (frames_written > 0)
return frames_written * frame_size;

View File

@ -53,14 +53,14 @@ private:
: std::chrono::steady_clock::duration::zero();
}
size_t Play([[maybe_unused]] const void *chunk, size_t size) override {
size_t Play(std::span<const std::byte> src) override {
if (sync) {
if (!timer->IsStarted())
timer->Start();
timer->Add(size);
timer->Add(src.size());
}
return size;
return src.size();
}
void Cancel() noexcept override {

View File

@ -112,7 +112,7 @@ private:
void Close() noexcept override;
std::chrono::steady_clock::duration Delay() const noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
bool Pause() override;
void Cancel() noexcept override;
};
@ -770,15 +770,13 @@ OSXOutput::Open(AudioFormat &audio_format)
started = false;
}
size_t
OSXOutput::Play(const void *chunk, size_t size)
std::size_t
OSXOutput::Play(std::span<const std::byte> input)
{
assert(size > 0);
pause = false;
std::span<const std::byte> input((const std::byte *)chunk, size);
#ifdef ENABLE_DSD
if (dop_enabled) {
input = pcm_export->Export(input);

View File

@ -69,7 +69,7 @@ private:
: std::chrono::milliseconds(50);
}
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Cancel() noexcept override;
@ -180,8 +180,8 @@ OpenALOutput::Close() noexcept
alcCloseDevice(device);
}
size_t
OpenALOutput::Play(const void *chunk, size_t size)
std::size_t
OpenALOutput::Play(std::span<const std::byte> src)
{
if (alcGetCurrentContext() != context)
alcMakeContextCurrent(context);
@ -199,13 +199,13 @@ OpenALOutput::Play(const void *chunk, size_t size)
alSourceUnqueueBuffers(source, 1, &buffer);
}
alBufferData(buffer, format, chunk, size, frequency);
alBufferData(buffer, format, src.data(), src.size(), frequency);
alSourceQueueBuffers(source, 1, &buffer);
if (!IsPlaying())
alSourcePlay(source);
return size;
return src.size();
}
void

View File

@ -114,7 +114,7 @@ public:
DoClose();
}
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Cancel() noexcept override;
private:
@ -679,26 +679,21 @@ OssOutput::Cancel() noexcept
pcm_export->Reset();
}
size_t
OssOutput::Play(const void *chunk, size_t size)
std::size_t
OssOutput::Play(std::span<const std::byte> src)
{
ssize_t ret;
assert(size > 0);
assert(!src.empty());
/* reopen the device since it was closed by dropBufferedAudio */
if (!fd.IsDefined())
Reopen();
const auto e = pcm_export->Export({(const std::byte *)chunk, size});
const auto e = pcm_export->Export(src);
if (e.empty())
return size;
chunk = e.data();
size = e.size();
return src.size();
while (true) {
ret = fd.Write(chunk, size);
const ssize_t ret = fd.Write(e.data(), e.size());
if (ret > 0)
return pcm_export->CalcInputSize(ret);

View File

@ -45,7 +45,7 @@ private:
pclose(fh);
}
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
};
PipeOutput::PipeOutput(const ConfigBlock &block)
@ -64,10 +64,10 @@ PipeOutput::Open([[maybe_unused]] AudioFormat &audio_format)
throw FormatErrno("Error opening pipe \"%s\"", cmd.c_str());
}
inline size_t
PipeOutput::Play(const void *chunk, size_t size)
std::size_t
PipeOutput::Play(std::span<const std::byte> src)
{
size_t nbytes = fwrite(chunk, 1, size, fh);
size_t nbytes = fwrite(src.data(), 1, src.size(), fh);
if (nbytes == 0)
throw MakeErrno("Write error on pipe");

View File

@ -290,7 +290,7 @@ private:
}
[[nodiscard]] std::chrono::steady_clock::duration Delay() const noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Drain() override;
void Cancel() noexcept override;
@ -828,8 +828,8 @@ PipeWireOutput::Delay() const noexcept
return result;
}
size_t
PipeWireOutput::Play(const void *chunk, size_t size)
std::size_t
PipeWireOutput::Play(std::span<const std::byte> src)
{
const PipeWire::ThreadLoopLock lock(thread_loop);
@ -839,7 +839,7 @@ PipeWireOutput::Play(const void *chunk, size_t size)
CheckThrowError();
std::size_t bytes_written =
ring_buffer->push((const std::byte *)chunk, size);
ring_buffer->push(src.data(), src.size());
if (bytes_written > 0) {
drained = false;
return bytes_written;

View File

@ -110,7 +110,7 @@ public:
void Interrupt() noexcept override;
[[nodiscard]] std::chrono::steady_clock::duration Delay() const noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Drain() override;
void Cancel() noexcept override;
bool Pause() override;
@ -775,8 +775,8 @@ PulseOutput::Delay() const noexcept
return result;
}
size_t
PulseOutput::Play(const void *chunk, size_t size)
std::size_t
PulseOutput::Play(std::span<const std::byte> src)
{
assert(mainloop != nullptr);
assert(stream != nullptr);
@ -811,18 +811,18 @@ PulseOutput::Play(const void *chunk, size_t size)
/* now write */
if (size > writable)
if (src.size() > writable)
/* don't send more than possible */
size = writable;
src = src.first(writable);
writable -= size;
writable -= src.size();
int result = pa_stream_write(stream, chunk, size, nullptr,
int result = pa_stream_write(stream, src.data(), src.size(), nullptr,
0, PA_SEEK_RELATIVE);
if (result < 0)
throw MakePulseError(context, "pa_stream_write() failed");
return size;
return src.size();
}
void

View File

@ -86,7 +86,7 @@ private:
void SendTag(const Tag &tag) override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
[[nodiscard]] gcc_pure
bool HasDynamicPath() const noexcept {
@ -322,22 +322,22 @@ RecorderOutput::SendTag(const Tag &tag)
encoder->SendTag(tag);
}
size_t
RecorderOutput::Play(const void *chunk, size_t size)
std::size_t
RecorderOutput::Play(std::span<const std::byte> src)
{
if (file == nullptr) {
/* not currently encoding to a file; discard incoming
data */
assert(HasDynamicPath());
assert(path.IsNull());
return size;
return src.size();
}
encoder->Write({(const std::byte *)chunk, size});
encoder->Write(src);
EncoderToFile();
return size;
return src.size();
}
const struct AudioOutputPlugin recorder_output_plugin = {

View File

@ -88,7 +88,7 @@ struct ShoutOutput final : AudioOutput {
[[nodiscard]] std::chrono::steady_clock::duration Delay() const noexcept override;
void SendTag(const Tag &tag) override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Cancel() noexcept override;
bool Pause() override;
@ -413,12 +413,12 @@ ShoutOutput::Delay() const noexcept
return std::chrono::milliseconds(delay);
}
size_t
ShoutOutput::Play(const void *chunk, size_t size)
std::size_t
ShoutOutput::Play(std::span<const std::byte> src)
{
encoder->Write({(const std::byte *)chunk, size});
encoder->Write(src);
WritePage();
return size;
return src.size();
}
bool

View File

@ -144,11 +144,9 @@ SndioOutput::Close() noexcept
}
size_t
SndioOutput::Play(const void *chunk, size_t size)
SndioOutput::Play(std::span<const std::byte> src)
{
size_t n;
n = sio_write(hdl, chunk, size);
const std::size_t n = sio_write(hdl, src.data(), src.size());
if (n == 0 && sio_eof(hdl) != 0)
throw std::runtime_error("sndio write failed");
return n;

View File

@ -49,7 +49,7 @@ public:
private:
void Open(AudioFormat &audio_format) override;
void Close() noexcept override;
size_t Play(const void *chunk, size_t size) override;
size_t Play(std::span<const std::byte> src) override;
};
#endif

View File

@ -76,7 +76,7 @@ private:
void Open(AudioFormat &audio_format) override;
void Close() noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Cancel() noexcept override;
};
@ -139,10 +139,10 @@ SolarisOutput::Close() noexcept
fd.Close();
}
size_t
SolarisOutput::Play(const void *chunk, size_t size)
std::size_t
SolarisOutput::Play(std::span<const std::byte> src)
{
ssize_t nbytes = fd.Write(chunk, size);
ssize_t nbytes = fd.Write(src.data(), src.size());
if (nbytes <= 0)
throw MakeErrno("Write failed");

View File

@ -69,7 +69,7 @@ private:
void Open(AudioFormat &audio_format) override;
void Close() noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Drain() override;
void Cancel() noexcept override;
@ -256,13 +256,13 @@ WinmmOutput::DrainBuffer(WinmmBuffer &buffer)
}
}
size_t
WinmmOutput::Play(const void *chunk, size_t size)
std::size_t
WinmmOutput::Play(std::span<const std::byte> src)
{
/* get the next buffer from the ring and prepare it */
WinmmBuffer *buffer = &buffers[next_buffer];
DrainBuffer(*buffer);
winmm_set_buffer(handle, buffer, chunk, size);
winmm_set_buffer(handle, buffer, src.data(), src.size());
/* enqueue the buffer */
MMRESULT result = waveOutWrite(handle, &buffer->hdr,
@ -276,7 +276,7 @@ WinmmOutput::Play(const void *chunk, size_t size)
/* mark our buffer as "used" */
next_buffer = (next_buffer + 1) % buffers.size();
return size;
return src.size();
}
void

View File

@ -254,7 +254,7 @@ public:
void SendTag(const Tag &tag) override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
/**
* Mutext must not be locked.

View File

@ -309,19 +309,19 @@ HttpdOutput::EncodeAndPlay(std::span<const std::byte> src)
BroadcastFromEncoder();
}
size_t
HttpdOutput::Play(const void *chunk, size_t size)
std::size_t
HttpdOutput::Play(std::span<const std::byte> src)
{
pause = false;
if (LockHasClients())
EncodeAndPlay({(const std::byte *)chunk, size});
EncodeAndPlay(src);
if (!timer->IsStarted())
timer->Start();
timer->Add(size);
timer->Add(src.size());
return size;
return src.size();
}
bool
@ -330,8 +330,8 @@ HttpdOutput::Pause()
pause = true;
if (LockHasClients()) {
static const char silence[1020] = { 0 };
Play(silence, sizeof(silence));
static constexpr std::byte silence[1020]{};
Play(std::span{silence});
}
return true;

View File

@ -99,7 +99,7 @@ private:
: std::chrono::steady_clock::duration::zero();
}
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Drain() override;
void Cancel() noexcept override;
@ -333,8 +333,8 @@ SlesOutput::Close() noexcept
engine_object.Destroy();
}
size_t
SlesOutput::Play(const void *chunk, size_t size)
std::size_t
SlesOutput::Play(std::span<const std::byte> src)
{
cancel = false;
@ -356,8 +356,8 @@ SlesOutput::Play(const void *chunk, size_t size)
return ret;
});
size_t nbytes = std::min(BUFFER_SIZE - filled, size);
memcpy(buffers[next] + filled, chunk, nbytes);
size_t nbytes = std::min(BUFFER_SIZE - filled, src.size());
memcpy(buffers[next] + filled, src.data(), nbytes);
filled += nbytes;
if (filled < BUFFER_SIZE)
return nbytes;

View File

@ -183,7 +183,7 @@ public:
void SendTag(const Tag &tag) override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Drain() override;
void Cancel() noexcept override;

View File

@ -297,8 +297,8 @@ SnapcastOutput::SendTag(const Tag &tag)
#endif
}
size_t
SnapcastOutput::Play(const void *chunk, size_t size)
std::size_t
SnapcastOutput::Play(std::span<const std::byte> src)
{
pause = false;
@ -306,13 +306,13 @@ SnapcastOutput::Play(const void *chunk, size_t size)
if (!timer->IsStarted())
timer->Start();
timer->Add(size);
timer->Add(src.size());
if (!LockHasClients())
return size;
return src.size();
encoder->Write({(const std::byte *)chunk, size});
unflushed_input += size;
encoder->Write(src);
unflushed_input += src.size();
if (unflushed_input >= 65536) {
/* we have fed a lot of input into the encoder, but it
@ -343,7 +343,7 @@ SnapcastOutput::Play(const void *chunk, size_t size)
chunks.push(std::make_shared<SnapcastChunk>(now, AllocatedArray{payload}));
}
return size;
return src.size();
}
bool

View File

@ -357,7 +357,7 @@ public:
}
void Close() noexcept override;
std::chrono::steady_clock::duration Delay() const noexcept override;
size_t Play(const void *chunk, size_t size) override;
std::size_t Play(std::span<const std::byte> src) override;
void Drain() override;
void Cancel() noexcept override;
bool Pause() override;
@ -707,8 +707,8 @@ WasapiOutput::Delay() const noexcept
return std::chrono::steady_clock::duration::zero();
}
size_t
WasapiOutput::Play(const void *chunk, size_t size)
std::size_t
WasapiOutput::Play(std::span<const std::byte> input)
{
assert(thread);
@ -716,12 +716,11 @@ WasapiOutput::Play(const void *chunk, size_t size)
not_interrupted.test_and_set();
std::span<const std::byte> input{(const std::byte*)chunk, size};
if (pcm_export) {
input = pcm_export->Export(input);
}
if (input.empty())
return size;
return input.size();
do {
const size_t consumed_size = thread->Push(input);

View File

@ -155,7 +155,7 @@ RunOutput(AudioOutput &ao, AudioFormat audio_format,
if (src.empty())
continue;
size_t consumed = ao.Play(src.data(), src.size());
size_t consumed = ao.Play(src);
assert(consumed <= src.size());
assert(consumed % in_frame_size == 0);