20 #include "../errors.hpp" 21 #include "../messages.h" 54 static void SDLCallback(
void *vsink, std::uint8_t *data,
int len)
56 assert(vsink !=
nullptr);
62 : bytes_per_sample(source.BytesPerSample()),
63 ring_buf(RINGBUF_POWER, source.BytesPerSample()),
64 position_sample_count(0),
68 const char *name = SDL_GetAudioDeviceName(device_id, 0);
69 if (name ==
nullptr) {
70 throw ConfigError(std::string(
"invalid device id: ") +
71 std::to_string(device_id));
79 want.callback = &SDLCallback;
80 want.userdata = (
void *)
this;
85 this->
device = SDL_OpenAudioDevice(name, 0, &want, &have, 0);
87 throw ConfigError(std::string(
"couldn't open device: ") +
94 if (this->
device == 0)
return;
97 SDL_PauseAudioDevice(this->
device, SDL_TRUE);
98 SDL_CloseAudioDevice(this->
device);
103 if (SDL_Init(SDL_INIT_AUDIO) != 0) {
104 throw ConfigError(std::string(
"could not initialise SDL: ") +
118 SDL_PauseAudioDevice(this->
device, 0);
126 SDL_PauseAudioDevice(this->
device, 1);
168 assert(start <= end);
171 if (start == end)
return;
173 unsigned long bytes = std::distance(start, end);
183 if (count == 0)
return;
185 auto start_ptr =
reinterpret_cast<char *
>(&*start);
186 unsigned long written_count = this->
ring_buf.
Write(start_ptr, count);
189 assert(written_count == count);
192 assert(start <= end);
197 assert(out !=
nullptr);
200 unsigned long lnbytes =
static_cast<unsigned long>(nbytes);
205 memset(out, 0, lnbytes);
222 if (avail_samples == 0) {
235 auto samples = std::min(req_samples, avail_samples);
237 this->
ring_buf.
Read(reinterpret_cast<char *>(out), samples);
243 std::vector<std::pair<int, std::string>> list;
246 int is = SDL_GetNumAudioDevices(0);
247 for (
int i = 0; i < is; i++) {
248 const char *n = SDL_GetAudioDeviceName(i, 0);
249 if (n !=
nullptr) list.emplace_back(i, std::string(n));
257 int ids = SDL_GetNumAudioDevices(0);
260 return (0 <=
id &&
id < ids);
void SourceOut() override
Tells this AudioSink that the source has run out.
Declaration of the AudioSource class.
State
Enumeration of possible states for this Audio.
static void CleanupLibrary()
Cleans up the AudioSink's libraries, if not cleaned up already.
void SetPosition(std::uint64_t samples) override
Sets the current played position, given a position in samples.
An object responsible for decoding an audio file.
The Audio is currently playing.
virtual std::uint8_t ChannelCount() const =0
Returns the channel count.
The Audio has ended and can't play without a seek.
An output stream for audio, using SDL.
AudioSource::DecodeVector::iterator TransferIterator
Type of iterators used in the Transfer() method.
void Transfer(TransferIterator &start, const TransferIterator &end) override
Transfers a range of sample bytes into the AudioSink.
RingBuffer ring_buf
The ring buffer used to transfer samples to the playing callback.
virtual SampleFormat OutputSampleFormat() const =0
Returns the output sample format.
SDL_AudioDeviceID device
The SDL device to which we are outputting sound.
void Callback(std::uint8_t *out, int nbytes)
The callback proper.
void Stop() override
Stops the audio stream.
std::uint64_t position_sample_count
The current position, in samples.
unsigned long Read(char *start, unsigned long count)
Reads samples from the ring buffer into an array.
virtual Audio::State State()
Gets this AudioSink's current state (playing/stopped/at end).
static bool IsOutputDevice(int id)
Can a sound device output sound?
size_t WriteCapacity() const
The current write capacity.
std::uint64_t Position() override
Gets the current played position in the song, in samples.
Audio::State State() override
Gets this AudioSink's current state (playing/stopped/at end).
static void InitLibrary()
Initialises the AudioSink's libraries, if not initialised already.
Declaration of the AudioSink class.
The RingBuffer class template.
bool source_out
Whether the source has run out of things to feed the sink.
SdlAudioSink(const AudioSource &source, int device_id)
Constructs an SdlAudioSink.
void Start() override
Starts the audio stream.
static const std::array< SDL_AudioFormat, SAMPLE_FORMAT_COUNT > FORMATS
Mapping from SampleFormats to their equivalent SDL_AudioFormats.
An Error signifying that playd has been improperly configured.
virtual std::uint32_t SampleRate() const =0
Returns the sample rate.
Audio::State state
The decoder's current state.
size_t ReadCapacity() const
The current read capacity.
unsigned long Write(const char *start, unsigned long count)
Writes samples from an array into the ring buffer.
size_t bytes_per_sample
Number of bytes in one sample.
~SdlAudioSink() override
Destructs an SdlAudioSink.
static std::vector< std::pair< int, std::string > > GetDevicesInfo()
Gets the number and name of each output device entry in the AudioSystem.
void Flush()
Empties the ring buffer.
static const size_t RINGBUF_POWER
n, where 2^n is the capacity of the Audio ring buffer.
The Audio has been stopped, or not yet played.