decoder/Client: add virtual method Ready()
Replaces decoder_initialized().
This commit is contained in:
parent
fd77acc217
commit
66fb352cca
@ -21,11 +21,27 @@
|
|||||||
#define MPD_DECODER_CLIENT_HXX
|
#define MPD_DECODER_CLIENT_HXX
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
#include "Chrono.hxx"
|
||||||
|
|
||||||
|
struct AudioFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface between the decoder plugin and the MPD core.
|
* An interface between the decoder plugin and the MPD core.
|
||||||
*/
|
*/
|
||||||
class DecoderClient {
|
class DecoderClient {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Notify the client that it has finished initialization and
|
||||||
|
* that it has read the song's meta data.
|
||||||
|
*
|
||||||
|
* @param audio_format the audio format which is going to be
|
||||||
|
* sent to SubmitData()
|
||||||
|
* @param seekable true if the song is seekable
|
||||||
|
* @param duration the total duration of this song; negative if
|
||||||
|
* unknown
|
||||||
|
*/
|
||||||
|
virtual void Ready(AudioFormat audio_format,
|
||||||
|
bool seekable, SignedSongTime duration) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -38,21 +38,18 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
decoder_initialized(DecoderClient &client,
|
Decoder::Ready(const AudioFormat audio_format,
|
||||||
const AudioFormat audio_format,
|
bool seekable, SignedSongTime duration)
|
||||||
bool seekable, SignedSongTime duration)
|
|
||||||
{
|
{
|
||||||
auto &decoder = (Decoder &)client;
|
|
||||||
DecoderControl &dc = decoder.dc;
|
|
||||||
struct audio_format_string af_string;
|
struct audio_format_string af_string;
|
||||||
|
|
||||||
assert(dc.state == DecoderState::START);
|
assert(dc.state == DecoderState::START);
|
||||||
assert(dc.pipe != nullptr);
|
assert(dc.pipe != nullptr);
|
||||||
assert(dc.pipe->IsEmpty());
|
assert(dc.pipe->IsEmpty());
|
||||||
assert(decoder.convert == nullptr);
|
assert(convert == nullptr);
|
||||||
assert(decoder.stream_tag == nullptr);
|
assert(stream_tag == nullptr);
|
||||||
assert(decoder.decoder_tag == nullptr);
|
assert(decoder_tag == nullptr);
|
||||||
assert(!decoder.seeking);
|
assert(!seeking);
|
||||||
assert(audio_format.IsDefined());
|
assert(audio_format.IsDefined());
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
@ -71,13 +68,13 @@ decoder_initialized(DecoderClient &client,
|
|||||||
audio_format_to_string(dc.out_audio_format,
|
audio_format_to_string(dc.out_audio_format,
|
||||||
&af_string));
|
&af_string));
|
||||||
|
|
||||||
decoder.convert = new PcmConvert();
|
convert = new PcmConvert();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
decoder.convert->Open(dc.in_audio_format,
|
convert->Open(dc.in_audio_format,
|
||||||
dc.out_audio_format);
|
dc.out_audio_format);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
decoder.error = std::current_exception();
|
error = std::current_exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
// IWYU pragma: begin_exports
|
// IWYU pragma: begin_exports
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
#include "Client.hxx"
|
||||||
#include "input/Ptr.hxx"
|
#include "input/Ptr.hxx"
|
||||||
#include "DecoderCommand.hxx"
|
#include "DecoderCommand.hxx"
|
||||||
#include "DecoderPlugin.hxx"
|
#include "DecoderPlugin.hxx"
|
||||||
@ -53,22 +54,6 @@ class DecoderClient;
|
|||||||
*/
|
*/
|
||||||
class StopDecoder {};
|
class StopDecoder {};
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the player thread that it has finished initialization and
|
|
||||||
* that it has read the song's meta data.
|
|
||||||
*
|
|
||||||
* @param decoder the decoder object
|
|
||||||
* @param audio_format the audio format which is going to be sent to
|
|
||||||
* decoder_data()
|
|
||||||
* @param seekable true if the song is seekable
|
|
||||||
* @param duration the total duration of this song; negative if
|
|
||||||
* unknown
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
decoder_initialized(DecoderClient &decoder,
|
|
||||||
AudioFormat audio_format,
|
|
||||||
bool seekable, SignedSongTime duration);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the pending decoder command.
|
* Determines the pending decoder command.
|
||||||
*
|
*
|
||||||
|
@ -116,6 +116,10 @@ struct Decoder final : DecoderClient {
|
|||||||
* Caller must not lock the #DecoderControl object.
|
* Caller must not lock the #DecoderControl object.
|
||||||
*/
|
*/
|
||||||
void FlushChunk();
|
void FlushChunk();
|
||||||
|
|
||||||
|
/* virtual methods from DecoderClient */
|
||||||
|
void Ready(AudioFormat audio_format,
|
||||||
|
bool seekable, SignedSongTime duration) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,8 +61,8 @@ adplug_file_decode(DecoderClient &client, Path path_fs)
|
|||||||
const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2);
|
const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2);
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, false,
|
client.Ready(audio_format, false,
|
||||||
SongTime::FromMS(player->songlength()));
|
SongTime::FromMS(player->songlength()));
|
||||||
|
|
||||||
DecoderCommand cmd;
|
DecoderCommand cmd;
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
const unsigned frame_size = (unsigned)
|
const unsigned frame_size = (unsigned)
|
||||||
afGetVirtualFrameSize(fh, AF_DEFAULT_TRACK, true);
|
afGetVirtualFrameSize(fh, AF_DEFAULT_TRACK, true);
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, true, total_time);
|
client.Ready(audio_format, true, total_time);
|
||||||
|
|
||||||
DecoderCommand cmd;
|
DecoderCommand cmd;
|
||||||
do {
|
do {
|
||||||
|
@ -437,7 +437,7 @@ dsdiff_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
audio_format.sample_rate);
|
audio_format.sample_rate);
|
||||||
|
|
||||||
/* success: file was recognized */
|
/* success: file was recognized */
|
||||||
decoder_initialized(client, audio_format, is.IsSeekable(), songtime);
|
client.Ready(audio_format, is.IsSeekable(), songtime);
|
||||||
|
|
||||||
/* every iteration of the following loop decodes one "DSD"
|
/* every iteration of the following loop decodes one "DSD"
|
||||||
chunk from a DFF file */
|
chunk from a DFF file */
|
||||||
|
@ -316,7 +316,7 @@ dsf_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
audio_format.sample_rate);
|
audio_format.sample_rate);
|
||||||
|
|
||||||
/* success: file was recognized */
|
/* success: file was recognized */
|
||||||
decoder_initialized(client, audio_format, is.IsSeekable(), songtime);
|
client.Ready(audio_format, is.IsSeekable(), songtime);
|
||||||
|
|
||||||
dsf_decode_chunk(client, is, metadata.channels,
|
dsf_decode_chunk(client, is, metadata.channels,
|
||||||
metadata.sample_rate,
|
metadata.sample_rate,
|
||||||
|
@ -339,7 +339,7 @@ faad_stream_decode(DecoderClient &client, InputStream &is,
|
|||||||
|
|
||||||
/* initialize the MPD core */
|
/* initialize the MPD core */
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, false, total_time);
|
client.Ready(audio_format, false, total_time);
|
||||||
|
|
||||||
/* the decoder loop */
|
/* the decoder loop */
|
||||||
|
|
||||||
|
@ -689,8 +689,7 @@ FfmpegDecode(DecoderClient &client, InputStream &input,
|
|||||||
const SignedSongTime total_time =
|
const SignedSongTime total_time =
|
||||||
FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base);
|
FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base);
|
||||||
|
|
||||||
decoder_initialized(client, audio_format,
|
client.Ready(audio_format, input.IsSeekable(), total_time);
|
||||||
input.IsSeekable(), total_time);
|
|
||||||
|
|
||||||
FfmpegParseMetaData(client, format_context, audio_stream);
|
FfmpegParseMetaData(client, format_context, audio_stream);
|
||||||
|
|
||||||
|
@ -52,9 +52,9 @@ FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample,
|
|||||||
audio_format.sample_rate)
|
audio_format.sample_rate)
|
||||||
: SignedSongTime::Negative();
|
: SignedSongTime::Negative();
|
||||||
|
|
||||||
decoder_initialized(*GetClient(), audio_format,
|
GetClient()->Ready(audio_format,
|
||||||
GetInputStream().IsSeekable(),
|
GetInputStream().IsSeekable(),
|
||||||
duration);
|
duration);
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
struct FlacDecoder : public FlacInput {
|
struct FlacDecoder : public FlacInput {
|
||||||
/**
|
/**
|
||||||
* Has decoder_initialized() been called yet?
|
* Has DecoderClient::Ready() been called yet?
|
||||||
*/
|
*/
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ struct FlacDecoder : public FlacInput {
|
|||||||
:FlacInput(_input_stream, &_client) {}
|
:FlacInput(_input_stream, &_client) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for decoder_initialized().
|
* Wrapper for DecoderClient::Ready().
|
||||||
*/
|
*/
|
||||||
bool Initialize(unsigned sample_rate, unsigned bits_per_sample,
|
bool Initialize(unsigned sample_rate, unsigned bits_per_sample,
|
||||||
unsigned channels, FLAC__uint64 total_frames);
|
unsigned channels, FLAC__uint64 total_frames);
|
||||||
@ -77,7 +77,7 @@ private:
|
|||||||
void OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc);
|
void OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function attempts to call decoder_initialized() in case there
|
* This function attempts to call DecoderClient::Ready() in case there
|
||||||
* was no STREAMINFO block. This is allowed for nonseekable streams,
|
* was no STREAMINFO block. This is allowed for nonseekable streams,
|
||||||
* where the server sends us only a part of the file, without
|
* where the server sends us only a part of the file, without
|
||||||
* providing the STREAMINFO block from the beginning of the file
|
* providing the STREAMINFO block from the beginning of the file
|
||||||
|
@ -160,8 +160,7 @@ fluidsynth_file_decode(DecoderClient &client, Path path_fs)
|
|||||||
MPD core */
|
MPD core */
|
||||||
|
|
||||||
const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2);
|
const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2);
|
||||||
decoder_initialized(client, audio_format, false,
|
client.Ready(audio_format, false, SignedSongTime::Negative());
|
||||||
SignedSongTime::Negative());
|
|
||||||
|
|
||||||
DecoderCommand cmd;
|
DecoderCommand cmd;
|
||||||
while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) {
|
while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) {
|
||||||
|
@ -171,7 +171,7 @@ gme_file_decode(DecoderClient &client, Path path_fs)
|
|||||||
SampleFormat::S16,
|
SampleFormat::S16,
|
||||||
GME_CHANNELS);
|
GME_CHANNELS);
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, true, song_len);
|
client.Ready(audio_format, true, song_len);
|
||||||
|
|
||||||
gme_err = gme_start_track(emu, container.track);
|
gme_err = gme_start_track(emu, container.track);
|
||||||
if (gme_err != nullptr)
|
if (gme_err != nullptr)
|
||||||
|
@ -1050,12 +1050,11 @@ mp3_decode(DecoderClient &client, InputStream &input_stream)
|
|||||||
|
|
||||||
data.AllocateBuffers();
|
data.AllocateBuffers();
|
||||||
|
|
||||||
decoder_initialized(client,
|
client.Ready(CheckAudioFormat(data.frame.header.samplerate,
|
||||||
CheckAudioFormat(data.frame.header.samplerate,
|
SampleFormat::S24_P32,
|
||||||
SampleFormat::S24_P32,
|
MAD_NCHANNELS(&data.frame.header)),
|
||||||
MAD_NCHANNELS(&data.frame.header)),
|
input_stream.IsSeekable(),
|
||||||
input_stream.IsSeekable(),
|
data.total_time);
|
||||||
data.total_time);
|
|
||||||
|
|
||||||
if (tag != nullptr) {
|
if (tag != nullptr) {
|
||||||
decoder_tag(client, input_stream, std::move(*tag));
|
decoder_tag(client, input_stream, std::move(*tag));
|
||||||
|
@ -170,8 +170,7 @@ mikmod_decoder_file_decode(DecoderClient &client, Path path_fs)
|
|||||||
const AudioFormat audio_format(mikmod_sample_rate, SampleFormat::S16, 2);
|
const AudioFormat audio_format(mikmod_sample_rate, SampleFormat::S16, 2);
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, false,
|
client.Ready(audio_format, false, SignedSongTime::Negative());
|
||||||
SignedSongTime::Negative());
|
|
||||||
|
|
||||||
Player_Start(handle);
|
Player_Start(handle);
|
||||||
|
|
||||||
|
@ -151,9 +151,8 @@ mod_decode(DecoderClient &client, InputStream &is)
|
|||||||
static constexpr AudioFormat audio_format(44100, SampleFormat::S16, 2);
|
static constexpr AudioFormat audio_format(44100, SampleFormat::S16, 2);
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
decoder_initialized(client, audio_format,
|
client.Ready(audio_format, is.IsSeekable(),
|
||||||
is.IsSeekable(),
|
SongTime::FromMS(ModPlug_GetLength(f)));
|
||||||
SongTime::FromMS(ModPlug_GetLength(f)));
|
|
||||||
|
|
||||||
DecoderCommand cmd;
|
DecoderCommand cmd;
|
||||||
do {
|
do {
|
||||||
|
@ -174,9 +174,8 @@ mpcdec_decode(DecoderClient &client, InputStream &is)
|
|||||||
|
|
||||||
decoder_replay_gain(client, &rgi);
|
decoder_replay_gain(client, &rgi);
|
||||||
|
|
||||||
decoder_initialized(client, audio_format,
|
client.Ready(audio_format, is.IsSeekable(),
|
||||||
is.IsSeekable(),
|
SongTime::FromS(mpc_streaminfo_get_length(&info)));
|
||||||
SongTime::FromS(mpc_streaminfo_get_length(&info)));
|
|
||||||
|
|
||||||
DecoderCommand cmd = DecoderCommand::NONE;
|
DecoderCommand cmd = DecoderCommand::NONE;
|
||||||
do {
|
do {
|
||||||
|
@ -210,7 +210,7 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
|
|||||||
SongTime::FromScale<uint64_t>(num_samples,
|
SongTime::FromScale<uint64_t>(num_samples,
|
||||||
audio_format.sample_rate);
|
audio_format.sample_rate);
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, true, duration);
|
client.Ready(audio_format, true, duration);
|
||||||
|
|
||||||
struct mpg123_frameinfo info;
|
struct mpg123_frameinfo info;
|
||||||
if (mpg123_info(handle, &info) != MPG123_OK) {
|
if (mpg123_info(handle, &info) != MPG123_OK) {
|
||||||
|
@ -93,7 +93,7 @@ public:
|
|||||||
~MPDOpusDecoder();
|
~MPDOpusDecoder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Has decoder_initialized() been called yet?
|
* Has DecoderClient::Ready() been called yet?
|
||||||
*/
|
*/
|
||||||
bool IsInitialized() const {
|
bool IsInitialized() const {
|
||||||
return previous_channels != 0;
|
return previous_channels != 0;
|
||||||
@ -175,8 +175,7 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
|
|||||||
previous_channels = channels;
|
previous_channels = channels;
|
||||||
const AudioFormat audio_format(opus_sample_rate,
|
const AudioFormat audio_format(opus_sample_rate,
|
||||||
SampleFormat::S16, channels);
|
SampleFormat::S16, channels);
|
||||||
decoder_initialized(client, audio_format,
|
client.Ready(audio_format, eos_granulepos > 0, duration);
|
||||||
eos_granulepos > 0, duration);
|
|
||||||
frame_size = audio_format.GetFrameSize();
|
frame_size = audio_format.GetFrameSize();
|
||||||
|
|
||||||
output_buffer = new opus_int16[opus_output_buffer_frames
|
output_buffer = new opus_int16[opus_output_buffer_frames
|
||||||
|
@ -143,8 +143,7 @@ pcm_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
audio_format.sample_rate)
|
audio_format.sample_rate)
|
||||||
: SignedSongTime::Negative();
|
: SignedSongTime::Negative();
|
||||||
|
|
||||||
decoder_initialized(client, audio_format,
|
client.Ready(audio_format, is.IsSeekable(), total_time);
|
||||||
is.IsSeekable(), total_time);
|
|
||||||
|
|
||||||
StaticFifoBuffer<uint8_t, 4096> buffer;
|
StaticFifoBuffer<uint8_t, 4096> buffer;
|
||||||
|
|
||||||
|
@ -337,7 +337,7 @@ sidplay_file_decode(DecoderClient &client, Path path_fs)
|
|||||||
const AudioFormat audio_format(48000, SampleFormat::S16, channels);
|
const AudioFormat audio_format(48000, SampleFormat::S16, channels);
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, true, duration);
|
client.Ready(audio_format, true, duration);
|
||||||
|
|
||||||
/* .. and play */
|
/* .. and play */
|
||||||
|
|
||||||
|
@ -205,8 +205,7 @@ sndfile_stream_decode(DecoderClient &client, InputStream &is)
|
|||||||
sndfile_sample_format(info),
|
sndfile_sample_format(info),
|
||||||
info.channels);
|
info.channels);
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, info.seekable,
|
client.Ready(audio_format, info.seekable, sndfile_duration(info));
|
||||||
sndfile_duration(info));
|
|
||||||
|
|
||||||
char buffer[16384];
|
char buffer[16384];
|
||||||
|
|
||||||
|
@ -175,8 +175,7 @@ VorbisDecoder::SubmitInit()
|
|||||||
audio_format.sample_rate)
|
audio_format.sample_rate)
|
||||||
: SignedSongTime::Negative();
|
: SignedSongTime::Negative();
|
||||||
|
|
||||||
decoder_initialized(client, audio_format,
|
client.Ready(audio_format, eos_granulepos > 0, duration);
|
||||||
eos_granulepos > 0, duration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -168,7 +168,7 @@ wavpack_decode(DecoderClient &client, WavpackContext *wpc, bool can_seek)
|
|||||||
const uint32_t samples_requested = ARRAY_SIZE(chunk) /
|
const uint32_t samples_requested = ARRAY_SIZE(chunk) /
|
||||||
audio_format.channels;
|
audio_format.channels;
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, can_seek, total_time);
|
client.Ready(audio_format, can_seek, total_time);
|
||||||
|
|
||||||
DecoderCommand cmd = decoder_get_command(client);
|
DecoderCommand cmd = decoder_get_command(client);
|
||||||
while (cmd != DecoderCommand::STOP) {
|
while (cmd != DecoderCommand::STOP) {
|
||||||
|
@ -103,7 +103,7 @@ wildmidi_file_decode(DecoderClient &client, Path path_fs)
|
|||||||
SongTime::FromScale<uint64_t>(info->approx_total_samples,
|
SongTime::FromScale<uint64_t>(info->approx_total_samples,
|
||||||
WILDMIDI_SAMPLE_RATE);
|
WILDMIDI_SAMPLE_RATE);
|
||||||
|
|
||||||
decoder_initialized(client, audio_format, true, duration);
|
client.Ready(audio_format, true, duration);
|
||||||
|
|
||||||
DecoderCommand cmd;
|
DecoderCommand cmd;
|
||||||
do {
|
do {
|
||||||
|
@ -29,22 +29,20 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
decoder_initialized(DecoderClient &client,
|
FakeDecoder::Ready(const AudioFormat audio_format,
|
||||||
const AudioFormat audio_format,
|
gcc_unused bool seekable,
|
||||||
gcc_unused bool seekable,
|
SignedSongTime duration)
|
||||||
SignedSongTime duration)
|
|
||||||
{
|
{
|
||||||
auto &decoder = (FakeDecoder &)client;
|
|
||||||
struct audio_format_string af_string;
|
struct audio_format_string af_string;
|
||||||
|
|
||||||
assert(!decoder.initialized);
|
assert(!initialized);
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
fprintf(stderr, "audio_format=%s duration=%f\n",
|
fprintf(stderr, "audio_format=%s duration=%f\n",
|
||||||
audio_format_to_string(audio_format, &af_string),
|
audio_format_to_string(audio_format, &af_string),
|
||||||
duration.ToDoubleS());
|
duration.ToDoubleS());
|
||||||
|
|
||||||
decoder.initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecoderCommand
|
DecoderCommand
|
||||||
|
@ -30,6 +30,10 @@ struct FakeDecoder final : DecoderClient {
|
|||||||
Cond cond;
|
Cond cond;
|
||||||
|
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
|
/* virtual methods from DecoderClient */
|
||||||
|
void Ready(AudioFormat audio_format,
|
||||||
|
bool seekable, SignedSongTime duration) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user