encoder/Interface: move instance methods to abstract class
Rename struct Encoder to PreparedEncoder, and add a new (abstract) class Encoder which represents one encoder instance.
This commit is contained in:
@@ -47,7 +47,8 @@ class RecorderOutput {
|
||||
/**
|
||||
* The configured encoder plugin.
|
||||
*/
|
||||
Encoder *encoder = nullptr;
|
||||
PreparedEncoder *prepared_encoder = nullptr;
|
||||
Encoder *encoder;
|
||||
|
||||
/**
|
||||
* The destination file name.
|
||||
@@ -75,8 +76,8 @@ class RecorderOutput {
|
||||
:base(recorder_output_plugin) {}
|
||||
|
||||
~RecorderOutput() {
|
||||
if (encoder != nullptr)
|
||||
encoder->Dispose();
|
||||
if (prepared_encoder != nullptr)
|
||||
prepared_encoder->Dispose();
|
||||
}
|
||||
|
||||
bool Initialize(const ConfigBlock &block, Error &error_r) {
|
||||
@@ -148,8 +149,8 @@ RecorderOutput::Configure(const ConfigBlock &block, Error &error)
|
||||
|
||||
/* initialize encoder */
|
||||
|
||||
encoder = encoder_init(*encoder_plugin, block, error);
|
||||
if (encoder == nullptr)
|
||||
prepared_encoder = encoder_init(*encoder_plugin, block, error);
|
||||
if (prepared_encoder == nullptr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -205,7 +206,8 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
|
||||
|
||||
/* open the encoder */
|
||||
|
||||
if (!encoder->Open(audio_format, error)) {
|
||||
encoder = prepared_encoder->Open(audio_format, error);
|
||||
if (encoder == nullptr) {
|
||||
delete file;
|
||||
return false;
|
||||
}
|
||||
@@ -214,7 +216,7 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
|
||||
try {
|
||||
EncoderToFile();
|
||||
} catch (const std::exception &e) {
|
||||
encoder->Close();
|
||||
delete encoder;
|
||||
error.Set(recorder_domain, e.what());
|
||||
return false;
|
||||
}
|
||||
@@ -224,7 +226,7 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
|
||||
|
||||
/* close the encoder for now; it will be opened as
|
||||
soon as we have received a tag */
|
||||
encoder->Close();
|
||||
delete encoder;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -237,19 +239,19 @@ RecorderOutput::Commit(Error &error)
|
||||
|
||||
/* flush the encoder and write the rest to the file */
|
||||
|
||||
bool success = encoder_end(encoder, error);
|
||||
bool success = encoder->End(error);
|
||||
if (success) {
|
||||
try {
|
||||
EncoderToFile();
|
||||
} catch (...) {
|
||||
encoder->Close();
|
||||
delete encoder;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/* now really close everything */
|
||||
|
||||
encoder->Close();
|
||||
delete encoder;
|
||||
|
||||
if (success) {
|
||||
try {
|
||||
@@ -326,7 +328,8 @@ RecorderOutput::ReopenFormat(AllocatedPath &&new_path, Error &error)
|
||||
}
|
||||
|
||||
AudioFormat new_audio_format = effective_audio_format;
|
||||
if (!encoder->Open(new_audio_format, error)) {
|
||||
encoder = prepared_encoder->Open(new_audio_format, error);
|
||||
if (encoder == nullptr) {
|
||||
delete new_file;
|
||||
return false;
|
||||
}
|
||||
@@ -338,7 +341,7 @@ RecorderOutput::ReopenFormat(AllocatedPath &&new_path, Error &error)
|
||||
try {
|
||||
EncoderToOutputStream(*new_file, *encoder);
|
||||
} catch (const std::exception &e) {
|
||||
encoder->Close();
|
||||
delete encoder;
|
||||
delete new_file;
|
||||
error.Set(recorder_domain, e.what());
|
||||
return false;
|
||||
@@ -386,7 +389,7 @@ RecorderOutput::SendTag(const Tag &tag)
|
||||
}
|
||||
|
||||
Error error;
|
||||
if (!encoder_pre_tag(encoder, error)) {
|
||||
if (!encoder->PreTag(error)) {
|
||||
LogError(error);
|
||||
return;
|
||||
}
|
||||
@@ -398,7 +401,7 @@ RecorderOutput::SendTag(const Tag &tag)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!encoder_tag(encoder, tag, error))
|
||||
if (!encoder->SendTag(tag, error))
|
||||
LogError(error);
|
||||
}
|
||||
|
||||
@@ -413,7 +416,7 @@ RecorderOutput::Play(const void *chunk, size_t size, Error &error)
|
||||
return size;
|
||||
}
|
||||
|
||||
if (!encoder_write(encoder, chunk, size, error))
|
||||
if (!encoder->Write(chunk, size, error))
|
||||
return 0;
|
||||
|
||||
try {
|
||||
|
@@ -45,7 +45,8 @@ struct ShoutOutput final {
|
||||
shout_t *shout_conn;
|
||||
shout_metadata_t *shout_meta;
|
||||
|
||||
Encoder *encoder = nullptr;
|
||||
PreparedEncoder *prepared_encoder = nullptr;
|
||||
Encoder *encoder;
|
||||
|
||||
float quality = -2.0;
|
||||
int bitrate = -1;
|
||||
@@ -93,8 +94,7 @@ ShoutOutput::~ShoutOutput()
|
||||
if (shout_init_count == 0)
|
||||
shout_shutdown();
|
||||
|
||||
if (encoder != nullptr)
|
||||
encoder->Dispose();
|
||||
delete prepared_encoder;
|
||||
}
|
||||
|
||||
static const EncoderPlugin *
|
||||
@@ -192,8 +192,8 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
|
||||
return false;
|
||||
}
|
||||
|
||||
encoder = encoder_init(*encoder_plugin, block, error);
|
||||
if (encoder == nullptr)
|
||||
prepared_encoder = encoder_init(*encoder_plugin, block, error);
|
||||
if (prepared_encoder == nullptr)
|
||||
return false;
|
||||
|
||||
unsigned shout_format;
|
||||
@@ -345,8 +345,8 @@ write_page(ShoutOutput *sd, Error &error)
|
||||
assert(sd->encoder != nullptr);
|
||||
|
||||
while (true) {
|
||||
size_t nbytes = encoder_read(sd->encoder,
|
||||
sd->buffer, sizeof(sd->buffer));
|
||||
size_t nbytes = sd->encoder->Read(sd->buffer,
|
||||
sizeof(sd->buffer));
|
||||
if (nbytes == 0)
|
||||
return true;
|
||||
|
||||
@@ -362,10 +362,10 @@ void
|
||||
ShoutOutput::Close()
|
||||
{
|
||||
if (encoder != nullptr) {
|
||||
if (encoder_end(encoder, IgnoreError()))
|
||||
if (encoder->End(IgnoreError()))
|
||||
write_page(this, IgnoreError());
|
||||
|
||||
encoder->Close();
|
||||
delete encoder;
|
||||
}
|
||||
|
||||
if (shout_get_connected(shout_conn) != SHOUTERR_UNCONNECTED &&
|
||||
@@ -406,13 +406,14 @@ ShoutOutput::Open(AudioFormat &audio_format, Error &error)
|
||||
if (!shout_connect(this, error))
|
||||
return false;
|
||||
|
||||
if (!encoder->Open(audio_format, error)) {
|
||||
encoder = prepared_encoder->Open(audio_format, error);
|
||||
if (encoder == nullptr) {
|
||||
shout_close(shout_conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_page(this, error)) {
|
||||
encoder->Close();
|
||||
delete encoder;
|
||||
shout_close(shout_conn);
|
||||
return false;
|
||||
}
|
||||
@@ -433,7 +434,7 @@ ShoutOutput::Delay() const
|
||||
size_t
|
||||
ShoutOutput::Play(const void *chunk, size_t size, Error &error)
|
||||
{
|
||||
return encoder_write(encoder, chunk, size, error) &&
|
||||
return encoder->Write(chunk, size, error) &&
|
||||
write_page(this, error)
|
||||
? size
|
||||
: 0;
|
||||
@@ -476,13 +477,13 @@ shout_tag_to_metadata(const Tag &tag, char *dest, size_t size)
|
||||
void
|
||||
ShoutOutput::SendTag(const Tag &tag)
|
||||
{
|
||||
if (encoder->plugin.tag != nullptr) {
|
||||
if (encoder->ImplementsTag()) {
|
||||
/* encoder plugin supports stream tags */
|
||||
|
||||
Error error;
|
||||
if (!encoder_pre_tag(encoder, error) ||
|
||||
if (!encoder->PreTag(error) ||
|
||||
!write_page(this, error) ||
|
||||
!encoder_tag(encoder, tag, error)) {
|
||||
!encoder->SendTag(tag, error)) {
|
||||
LogError(error);
|
||||
return;
|
||||
}
|
||||
|
@@ -45,7 +45,8 @@ class EventLoop;
|
||||
class ServerSocket;
|
||||
class HttpdClient;
|
||||
class Page;
|
||||
struct Encoder;
|
||||
struct PreparedEncoder;
|
||||
class Encoder;
|
||||
struct Tag;
|
||||
|
||||
class HttpdOutput final : ServerSocket, DeferredMonitor {
|
||||
@@ -60,6 +61,7 @@ class HttpdOutput final : ServerSocket, DeferredMonitor {
|
||||
/**
|
||||
* The configured encoder plugin.
|
||||
*/
|
||||
PreparedEncoder *prepared_encoder = nullptr;
|
||||
Encoder *encoder;
|
||||
|
||||
/**
|
||||
|
@@ -63,8 +63,8 @@ HttpdOutput::~HttpdOutput()
|
||||
if (metadata != nullptr)
|
||||
metadata->Unref();
|
||||
|
||||
if (encoder != nullptr)
|
||||
encoder->Dispose();
|
||||
if (prepared_encoder != nullptr)
|
||||
prepared_encoder->Dispose();
|
||||
|
||||
}
|
||||
|
||||
@@ -123,12 +123,12 @@ HttpdOutput::Configure(const ConfigBlock &block, Error &error)
|
||||
|
||||
/* initialize encoder */
|
||||
|
||||
encoder = encoder_init(*encoder_plugin, block, error);
|
||||
if (encoder == nullptr)
|
||||
prepared_encoder = encoder_init(*encoder_plugin, block, error);
|
||||
if (prepared_encoder == nullptr)
|
||||
return false;
|
||||
|
||||
/* determine content type */
|
||||
content_type = encoder_get_mime_type(encoder);
|
||||
content_type = encoder_get_mime_type(prepared_encoder);
|
||||
if (content_type == nullptr)
|
||||
content_type = "application/octet-stream";
|
||||
|
||||
@@ -169,7 +169,7 @@ inline void
|
||||
HttpdOutput::AddClient(int fd)
|
||||
{
|
||||
auto *client = new HttpdClient(*this, fd, GetEventLoop(),
|
||||
encoder->plugin.tag == nullptr);
|
||||
!encoder->ImplementsTag());
|
||||
clients.push_front(*client);
|
||||
|
||||
/* pass metadata to client */
|
||||
@@ -250,15 +250,14 @@ HttpdOutput::ReadPage()
|
||||
/* we have fed a lot of input into the encoder, but it
|
||||
didn't give anything back yet - flush now to avoid
|
||||
buffer underruns */
|
||||
encoder_flush(encoder, IgnoreError());
|
||||
encoder->Flush(IgnoreError());
|
||||
unflushed_input = 0;
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
do {
|
||||
size_t nbytes = encoder_read(encoder,
|
||||
buffer + size,
|
||||
sizeof(buffer) - size);
|
||||
size_t nbytes = encoder->Read(buffer + size,
|
||||
sizeof(buffer) - size);
|
||||
if (nbytes == 0)
|
||||
break;
|
||||
|
||||
@@ -292,7 +291,8 @@ httpd_output_disable(AudioOutput *ao)
|
||||
inline bool
|
||||
HttpdOutput::OpenEncoder(AudioFormat &audio_format, Error &error)
|
||||
{
|
||||
if (!encoder->Open(audio_format, error))
|
||||
encoder = prepared_encoder->Open(audio_format, error);
|
||||
if (encoder == nullptr)
|
||||
return false;
|
||||
|
||||
/* we have to remember the encoder header, i.e. the first
|
||||
@@ -351,7 +351,7 @@ HttpdOutput::Close()
|
||||
if (header != nullptr)
|
||||
header->Unref();
|
||||
|
||||
encoder->Close();
|
||||
delete encoder;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -441,7 +441,7 @@ HttpdOutput::BroadcastFromEncoder()
|
||||
inline bool
|
||||
HttpdOutput::EncodeAndPlay(const void *chunk, size_t size, Error &error)
|
||||
{
|
||||
if (!encoder_write(encoder, chunk, size, error))
|
||||
if (!encoder->Write(chunk, size, error))
|
||||
return false;
|
||||
|
||||
unflushed_input += size;
|
||||
@@ -491,18 +491,18 @@ httpd_output_pause(AudioOutput *ao)
|
||||
inline void
|
||||
HttpdOutput::SendTag(const Tag &tag)
|
||||
{
|
||||
if (encoder->plugin.tag != nullptr) {
|
||||
if (encoder->ImplementsTag()) {
|
||||
/* embed encoder tags */
|
||||
|
||||
/* flush the current stream, and end it */
|
||||
|
||||
encoder_pre_tag(encoder, IgnoreError());
|
||||
encoder->PreTag(IgnoreError());
|
||||
BroadcastFromEncoder();
|
||||
|
||||
/* send the tag to the encoder - which starts a new
|
||||
stream now */
|
||||
|
||||
encoder_tag(encoder, tag, IgnoreError());
|
||||
encoder->SendTag(tag, IgnoreError());
|
||||
|
||||
/* the first page generated by the encoder will now be
|
||||
used as the new "header" page, which is sent to all
|
||||
|
Reference in New Issue
Block a user