util/Error: new error passing library
Replaces GLib's GError.
This commit is contained in:
@@ -23,6 +23,8 @@
|
||||
#include "MixerList.hxx"
|
||||
#include "pcm/PcmExport.hxx"
|
||||
#include "util/Manual.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <glib.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
@@ -115,9 +117,9 @@ struct AlsaOutput {
|
||||
AlsaOutput():mode(0), writei(snd_pcm_writei) {
|
||||
}
|
||||
|
||||
bool Init(const config_param ¶m, GError **error_r) {
|
||||
bool Init(const config_param ¶m, Error &error) {
|
||||
return ao_base_init(&base, &alsa_output_plugin,
|
||||
param, error_r);
|
||||
param, error);
|
||||
}
|
||||
|
||||
void Deinit() {
|
||||
@@ -125,14 +127,7 @@ struct AlsaOutput {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
alsa_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("alsa_output");
|
||||
}
|
||||
static constexpr Domain alsa_output_domain("alsa_output");
|
||||
|
||||
static const char *
|
||||
alsa_device(const AlsaOutput *ad)
|
||||
@@ -170,11 +165,11 @@ alsa_configure(AlsaOutput *ad, const config_param ¶m)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
alsa_init(const config_param ¶m, GError **error_r)
|
||||
alsa_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
AlsaOutput *ad = new AlsaOutput();
|
||||
|
||||
if (!ad->Init(param, error_r)) {
|
||||
if (!ad->Init(param, error)) {
|
||||
delete ad;
|
||||
return NULL;
|
||||
}
|
||||
@@ -197,7 +192,7 @@ alsa_finish(struct audio_output *ao)
|
||||
}
|
||||
|
||||
static bool
|
||||
alsa_output_enable(struct audio_output *ao, gcc_unused GError **error_r)
|
||||
alsa_output_enable(struct audio_output *ao, gcc_unused Error &error)
|
||||
{
|
||||
AlsaOutput *ad = (AlsaOutput *)ao;
|
||||
|
||||
@@ -394,7 +389,7 @@ alsa_output_setup_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
|
||||
*/
|
||||
static bool
|
||||
alsa_setup(AlsaOutput *ad, AudioFormat &audio_format,
|
||||
bool *packed_r, bool *reverse_endian_r, GError **error)
|
||||
bool *packed_r, bool *reverse_endian_r, Error &error)
|
||||
{
|
||||
unsigned int sample_rate = audio_format.sample_rate;
|
||||
unsigned int channels = audio_format.channels;
|
||||
@@ -438,11 +433,11 @@ configure_hw:
|
||||
err = alsa_output_setup_format(ad->pcm, hwparams, audio_format,
|
||||
packed_r, reverse_endian_r);
|
||||
if (err < 0) {
|
||||
g_set_error(error, alsa_output_quark(), err,
|
||||
"ALSA device \"%s\" does not support format %s: %s",
|
||||
alsa_device(ad),
|
||||
sample_format_to_string(audio_format.format),
|
||||
snd_strerror(-err));
|
||||
error.Format(alsa_output_domain, err,
|
||||
"ALSA device \"%s\" does not support format %s: %s",
|
||||
alsa_device(ad),
|
||||
sample_format_to_string(audio_format.format),
|
||||
snd_strerror(-err));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -454,10 +449,10 @@ configure_hw:
|
||||
err = snd_pcm_hw_params_set_channels_near(ad->pcm, hwparams,
|
||||
&channels);
|
||||
if (err < 0) {
|
||||
g_set_error(error, alsa_output_quark(), err,
|
||||
"ALSA device \"%s\" does not support %i channels: %s",
|
||||
alsa_device(ad), (int)audio_format.channels,
|
||||
snd_strerror(-err));
|
||||
error.Format(alsa_output_domain, err,
|
||||
"ALSA device \"%s\" does not support %i channels: %s",
|
||||
alsa_device(ad), (int)audio_format.channels,
|
||||
snd_strerror(-err));
|
||||
return false;
|
||||
}
|
||||
audio_format.channels = (int8_t)channels;
|
||||
@@ -465,9 +460,9 @@ configure_hw:
|
||||
err = snd_pcm_hw_params_set_rate_near(ad->pcm, hwparams,
|
||||
&sample_rate, NULL);
|
||||
if (err < 0 || sample_rate == 0) {
|
||||
g_set_error(error, alsa_output_quark(), err,
|
||||
"ALSA device \"%s\" does not support %u Hz audio",
|
||||
alsa_device(ad), audio_format.sample_rate);
|
||||
error.Format(alsa_output_domain, err,
|
||||
"ALSA device \"%s\" does not support %u Hz audio",
|
||||
alsa_device(ad), audio_format.sample_rate);
|
||||
return false;
|
||||
}
|
||||
audio_format.sample_rate = sample_rate;
|
||||
@@ -594,16 +589,16 @@ configure_hw:
|
||||
return true;
|
||||
|
||||
error:
|
||||
g_set_error(error, alsa_output_quark(), err,
|
||||
"Error opening ALSA device \"%s\" (%s): %s",
|
||||
alsa_device(ad), cmd, snd_strerror(-err));
|
||||
error.Format(alsa_output_domain, err,
|
||||
"Error opening ALSA device \"%s\" (%s): %s",
|
||||
alsa_device(ad), cmd, snd_strerror(-err));
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
alsa_setup_dsd(AlsaOutput *ad, const AudioFormat audio_format,
|
||||
bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
assert(ad->dsd_usb);
|
||||
assert(audio_format.format == SampleFormat::DSD);
|
||||
@@ -616,7 +611,7 @@ alsa_setup_dsd(AlsaOutput *ad, const AudioFormat audio_format,
|
||||
|
||||
const AudioFormat check = usb_format;
|
||||
|
||||
if (!alsa_setup(ad, usb_format, packed_r, reverse_endian_r, error_r))
|
||||
if (!alsa_setup(ad, usb_format, packed_r, reverse_endian_r, error))
|
||||
return false;
|
||||
|
||||
/* if the device allows only 32 bit, shift all DSD-over-USB
|
||||
@@ -631,9 +626,9 @@ alsa_setup_dsd(AlsaOutput *ad, const AudioFormat audio_format,
|
||||
if (usb_format != check) {
|
||||
/* no bit-perfect playback, which is required
|
||||
for DSD over USB */
|
||||
g_set_error(error_r, alsa_output_quark(), 0,
|
||||
"Failed to configure DSD-over-USB on ALSA device \"%s\"",
|
||||
alsa_device(ad));
|
||||
error.Format(alsa_output_domain,
|
||||
"Failed to configure DSD-over-USB on ALSA device \"%s\"",
|
||||
alsa_device(ad));
|
||||
g_free(ad->silence);
|
||||
return false;
|
||||
}
|
||||
@@ -643,7 +638,7 @@ alsa_setup_dsd(AlsaOutput *ad, const AudioFormat audio_format,
|
||||
|
||||
static bool
|
||||
alsa_setup_or_dsd(AlsaOutput *ad, AudioFormat &audio_format,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
bool shift8 = false, packed, reverse_endian;
|
||||
|
||||
@@ -652,9 +647,9 @@ alsa_setup_or_dsd(AlsaOutput *ad, AudioFormat &audio_format,
|
||||
const bool success = dsd_usb
|
||||
? alsa_setup_dsd(ad, audio_format,
|
||||
&shift8, &packed, &reverse_endian,
|
||||
error_r)
|
||||
error)
|
||||
: alsa_setup(ad, audio_format, &packed, &reverse_endian,
|
||||
error_r);
|
||||
error);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
@@ -665,14 +660,14 @@ alsa_setup_or_dsd(AlsaOutput *ad, AudioFormat &audio_format,
|
||||
}
|
||||
|
||||
static bool
|
||||
alsa_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
|
||||
alsa_open(struct audio_output *ao, AudioFormat &audio_format, Error &error)
|
||||
{
|
||||
AlsaOutput *ad = (AlsaOutput *)ao;
|
||||
|
||||
int err = snd_pcm_open(&ad->pcm, alsa_device(ad),
|
||||
SND_PCM_STREAM_PLAYBACK, ad->mode);
|
||||
if (err < 0) {
|
||||
g_set_error(error, alsa_output_quark(), err,
|
||||
error.Format(alsa_output_domain, err,
|
||||
"Failed to open ALSA device \"%s\": %s",
|
||||
alsa_device(ad), snd_strerror(err));
|
||||
return false;
|
||||
@@ -800,7 +795,7 @@ alsa_close(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
alsa_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
AlsaOutput *ad = (AlsaOutput *)ao;
|
||||
|
||||
@@ -824,8 +819,7 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
|
||||
if (ret < 0 && ret != -EAGAIN && ret != -EINTR &&
|
||||
alsa_recover(ad, ret) < 0) {
|
||||
g_set_error(error, alsa_output_quark(), errno,
|
||||
"%s", snd_strerror(-errno));
|
||||
error.Set(alsa_output_domain, ret, snd_strerror(-ret));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#include "config.h"
|
||||
#include "AoOutputPlugin.hxx"
|
||||
#include "OutputAPI.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <ao/ao.h>
|
||||
#include <glib.h>
|
||||
@@ -42,26 +44,22 @@ struct AoOutput {
|
||||
ao_option *options;
|
||||
ao_device *device;
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error) {
|
||||
return ao_base_init(&base, &ao_output_plugin, param,
|
||||
error_r);
|
||||
error);
|
||||
}
|
||||
|
||||
void Deinitialize() {
|
||||
ao_base_finish(&base);
|
||||
}
|
||||
|
||||
bool Configure(const config_param ¶m, GError **error_r);
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
};
|
||||
|
||||
static inline GQuark
|
||||
ao_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("ao_output");
|
||||
}
|
||||
static constexpr Domain ao_output_domain("ao_output");
|
||||
|
||||
static void
|
||||
ao_output_error(GError **error_r)
|
||||
ao_output_error(Error &error_r)
|
||||
{
|
||||
const char *error;
|
||||
|
||||
@@ -87,15 +85,15 @@ ao_output_error(GError **error_r)
|
||||
break;
|
||||
|
||||
default:
|
||||
error = g_strerror(errno);
|
||||
error_r.SetErrno();
|
||||
return;
|
||||
}
|
||||
|
||||
g_set_error(error_r, ao_output_quark(), errno,
|
||||
"%s", error);
|
||||
error_r.Set(ao_output_domain, errno, error);
|
||||
}
|
||||
|
||||
inline bool
|
||||
AoOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
AoOutput::Configure(const config_param ¶m, Error &error)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
@@ -115,16 +113,15 @@ AoOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
driver = ao_driver_id(value);
|
||||
|
||||
if (driver < 0) {
|
||||
g_set_error(error_r, ao_output_quark(), 0,
|
||||
"\"%s\" is not a valid ao driver",
|
||||
value);
|
||||
error.Format(ao_output_domain,
|
||||
"\"%s\" is not a valid ao driver",
|
||||
value);
|
||||
return false;
|
||||
}
|
||||
|
||||
ao_info *ai = ao_driver_info(driver);
|
||||
if (ai == nullptr) {
|
||||
g_set_error(error_r, ao_output_quark(), 0,
|
||||
"problems getting driver info");
|
||||
error.Set(ao_output_domain, "problems getting driver info");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -139,9 +136,9 @@ AoOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
gchar **key_value = g_strsplit(_options[i], "=", 2);
|
||||
|
||||
if (key_value[0] == nullptr || key_value[1] == nullptr) {
|
||||
g_set_error(error_r, ao_output_quark(), 0,
|
||||
"problems parsing options \"%s\"",
|
||||
_options[i]);
|
||||
error.Format(ao_output_domain,
|
||||
"problems parsing options \"%s\"",
|
||||
_options[i]);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -158,16 +155,16 @@ AoOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
ao_output_init(const config_param ¶m, GError **error_r)
|
||||
ao_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
AoOutput *ad = new AoOutput();
|
||||
|
||||
if (!ad->Initialize(param, error_r)) {
|
||||
if (!ad->Initialize(param, error)) {
|
||||
delete ad;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ad->Configure(param, error_r)) {
|
||||
if (!ad->Configure(param, error)) {
|
||||
ad->Deinitialize();
|
||||
delete ad;
|
||||
return nullptr;
|
||||
@@ -201,7 +198,7 @@ ao_output_close(struct audio_output *ao)
|
||||
|
||||
static bool
|
||||
ao_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
ao_sample_format format = OUR_AO_FORMAT_INITIALIZER;
|
||||
AoOutput *ad = (AoOutput *)ao;
|
||||
@@ -257,7 +254,7 @@ static int ao_play_deconst(ao_device *device, const void *output_samples,
|
||||
|
||||
static size_t
|
||||
ao_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
AoOutput *ad = (AoOutput *)ao;
|
||||
|
||||
|
@@ -19,11 +19,14 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "FifoOutputPlugin.hxx"
|
||||
#include "ConfigError.hxx"
|
||||
#include "OutputAPI.hxx"
|
||||
#include "Timer.hxx"
|
||||
#include "system/fd_util.h"
|
||||
#include "fs/Path.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "open.h"
|
||||
|
||||
#include <glib.h>
|
||||
@@ -53,31 +56,24 @@ struct FifoOutput {
|
||||
FifoOutput()
|
||||
:path(Path::Null()), input(-1), output(-1), created(false) {}
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error) {
|
||||
return ao_base_init(&base, &fifo_output_plugin, param,
|
||||
error_r);
|
||||
error);
|
||||
}
|
||||
|
||||
void Deinitialize() {
|
||||
ao_base_finish(&base);
|
||||
}
|
||||
|
||||
bool Create(GError **error_r);
|
||||
bool Check(GError **error_r);
|
||||
bool Create(Error &error);
|
||||
bool Check(Error &error);
|
||||
void Delete();
|
||||
|
||||
bool Open(GError **error_r);
|
||||
bool Open(Error &error);
|
||||
void Close();
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
fifo_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("fifo_output");
|
||||
}
|
||||
static constexpr Domain fifo_output_domain("fifo_output");
|
||||
|
||||
inline void
|
||||
FifoOutput::Delete()
|
||||
@@ -112,12 +108,11 @@ FifoOutput::Close()
|
||||
}
|
||||
|
||||
inline bool
|
||||
FifoOutput::Create(GError **error_r)
|
||||
FifoOutput::Create(Error &error)
|
||||
{
|
||||
if (!MakeFifo(path, 0666)) {
|
||||
g_set_error(error_r, fifo_output_quark(), errno,
|
||||
"Couldn't create FIFO \"%s\": %s",
|
||||
path_utf8.c_str(), g_strerror(errno));
|
||||
error.FormatErrno("Couldn't create FIFO \"%s\"",
|
||||
path_utf8.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,25 +121,24 @@ FifoOutput::Create(GError **error_r)
|
||||
}
|
||||
|
||||
inline bool
|
||||
FifoOutput::Check(GError **error_r)
|
||||
FifoOutput::Check(Error &error)
|
||||
{
|
||||
struct stat st;
|
||||
if (!StatFile(path, st)) {
|
||||
if (errno == ENOENT) {
|
||||
/* Path doesn't exist */
|
||||
return Create(error_r);
|
||||
return Create(error);
|
||||
}
|
||||
|
||||
g_set_error(error_r, fifo_output_quark(), errno,
|
||||
"Failed to stat FIFO \"%s\": %s",
|
||||
path_utf8.c_str(), g_strerror(errno));
|
||||
error.FormatErrno("Failed to stat FIFO \"%s\"",
|
||||
path_utf8.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!S_ISFIFO(st.st_mode)) {
|
||||
g_set_error(error_r, fifo_output_quark(), 0,
|
||||
"\"%s\" already exists, but is not a FIFO",
|
||||
path_utf8.c_str());
|
||||
error.Format(fifo_output_domain,
|
||||
"\"%s\" already exists, but is not a FIFO",
|
||||
path_utf8.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -152,25 +146,23 @@ FifoOutput::Check(GError **error_r)
|
||||
}
|
||||
|
||||
inline bool
|
||||
FifoOutput::Open(GError **error_r)
|
||||
FifoOutput::Open(Error &error)
|
||||
{
|
||||
if (!Check(error_r))
|
||||
if (!Check(error))
|
||||
return false;
|
||||
|
||||
input = OpenFile(path, O_RDONLY|O_NONBLOCK|O_BINARY, 0);
|
||||
if (input < 0) {
|
||||
g_set_error(error_r, fifo_output_quark(), errno,
|
||||
"Could not open FIFO \"%s\" for reading: %s",
|
||||
path_utf8.c_str(), g_strerror(errno));
|
||||
error.FormatErrno("Could not open FIFO \"%s\" for reading",
|
||||
path_utf8.c_str());
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
output = OpenFile(path, O_WRONLY|O_NONBLOCK|O_BINARY, 0);
|
||||
if (output < 0) {
|
||||
g_set_error(error_r, fifo_output_quark(), errno,
|
||||
"Could not open FIFO \"%s\" for writing: %s",
|
||||
path_utf8.c_str(), g_strerror(errno));
|
||||
error.FormatErrno("Could not open FIFO \"%s\" for writing",
|
||||
path_utf8.c_str());
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
@@ -179,37 +171,34 @@ FifoOutput::Open(GError **error_r)
|
||||
}
|
||||
|
||||
static bool
|
||||
fifo_open(FifoOutput *fd, GError **error_r)
|
||||
fifo_open(FifoOutput *fd, Error &error)
|
||||
{
|
||||
return fd->Open(error_r);
|
||||
return fd->Open(error);
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
fifo_output_init(const config_param ¶m, GError **error_r)
|
||||
fifo_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
GError *error = nullptr;
|
||||
|
||||
FifoOutput *fd = new FifoOutput();
|
||||
|
||||
fd->path = param.GetBlockPath("path", &error);
|
||||
fd->path = param.GetBlockPath("path", error);
|
||||
if (fd->path.IsNull()) {
|
||||
delete fd;
|
||||
if (error != nullptr)
|
||||
g_propagate_error(error_r, error);
|
||||
else
|
||||
g_set_error(error_r, fifo_output_quark(), 0,
|
||||
"No \"path\" parameter specified");
|
||||
|
||||
if (!error.IsDefined())
|
||||
error.Set(config_domain,
|
||||
"No \"path\" parameter specified");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fd->path_utf8 = fd->path.ToUTF8();
|
||||
|
||||
if (!fd->Initialize(param, error_r)) {
|
||||
if (!fd->Initialize(param, error)) {
|
||||
delete fd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!fifo_open(fd, error_r)) {
|
||||
if (!fifo_open(fd, error)) {
|
||||
fd->Deinitialize();
|
||||
delete fd;
|
||||
return nullptr;
|
||||
@@ -230,7 +219,7 @@ fifo_output_finish(struct audio_output *ao)
|
||||
|
||||
static bool
|
||||
fifo_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
gcc_unused GError **error)
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
FifoOutput *fd = (FifoOutput *)ao;
|
||||
|
||||
@@ -277,7 +266,7 @@ fifo_output_delay(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
fifo_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
FifoOutput *fd = (FifoOutput *)ao;
|
||||
ssize_t bytes;
|
||||
@@ -301,9 +290,8 @@ fifo_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
continue;
|
||||
}
|
||||
|
||||
g_set_error(error, fifo_output_quark(), errno,
|
||||
"Failed to write to FIFO %s: %s",
|
||||
fd->path_utf8.c_str(), g_strerror(errno));
|
||||
error.FormatErrno("Failed to write to FIFO %s",
|
||||
fd->path_utf8.c_str());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -431,10 +431,9 @@ HttpdClient::OnSocketInput(const void *data, size_t length)
|
||||
}
|
||||
|
||||
void
|
||||
HttpdClient::OnSocketError(GError *error)
|
||||
HttpdClient::OnSocketError(Error &&error)
|
||||
{
|
||||
g_warning("error on HTTP client: %s", error->message);
|
||||
g_error_free(error);
|
||||
g_warning("error on HTTP client: %s", error.GetMessage());
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -179,7 +179,7 @@ protected:
|
||||
virtual bool OnSocketReady(unsigned flags) override;
|
||||
virtual InputResult OnSocketInput(const void *data,
|
||||
size_t length) override;
|
||||
virtual void OnSocketError(GError *error) override;
|
||||
virtual void OnSocketError(Error &&error) override;
|
||||
virtual void OnSocketClosed() override;
|
||||
};
|
||||
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <forward_list>
|
||||
|
||||
struct config_param;
|
||||
class Error;
|
||||
class EventLoop;
|
||||
class ServerSocket;
|
||||
class HttpdClient;
|
||||
@@ -123,21 +124,20 @@ struct HttpdOutput final : private ServerSocket {
|
||||
HttpdOutput(EventLoop &_loop);
|
||||
~HttpdOutput();
|
||||
|
||||
bool Configure(const config_param ¶m, GError **error_r);
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
|
||||
bool Bind(GError **error_r);
|
||||
bool Bind(Error &error);
|
||||
void Unbind();
|
||||
|
||||
/**
|
||||
* Caller must lock the mutex.
|
||||
*/
|
||||
bool OpenEncoder(AudioFormat &audio_format,
|
||||
GError **error_r);
|
||||
bool OpenEncoder(AudioFormat &audio_format, Error &error);
|
||||
|
||||
/**
|
||||
* Caller must lock the mutex.
|
||||
*/
|
||||
bool Open(AudioFormat &audio_format, GError **error_r);
|
||||
bool Open(AudioFormat &audio_format, Error &error);
|
||||
|
||||
/**
|
||||
* Caller must lock the mutex.
|
||||
@@ -194,7 +194,7 @@ struct HttpdOutput final : private ServerSocket {
|
||||
*/
|
||||
void BroadcastFromEncoder();
|
||||
|
||||
bool EncodeAndPlay(const void *chunk, size_t size, GError **error_r);
|
||||
bool EncodeAndPlay(const void *chunk, size_t size, Error &error);
|
||||
|
||||
void SendTag(const Tag *tag);
|
||||
|
||||
|
@@ -29,6 +29,8 @@
|
||||
#include "IcyMetaDataServer.hxx"
|
||||
#include "system/fd_util.h"
|
||||
#include "Main.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -45,14 +47,7 @@
|
||||
#undef G_LOG_DOMAIN
|
||||
#define G_LOG_DOMAIN "httpd_output"
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
httpd_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("httpd_output");
|
||||
}
|
||||
static constexpr Domain httpd_output_domain("httpd_output");
|
||||
|
||||
inline
|
||||
HttpdOutput::HttpdOutput(EventLoop &_loop)
|
||||
@@ -73,12 +68,12 @@ HttpdOutput::~HttpdOutput()
|
||||
}
|
||||
|
||||
inline bool
|
||||
HttpdOutput::Bind(GError **error_r)
|
||||
HttpdOutput::Bind(Error &error)
|
||||
{
|
||||
open = false;
|
||||
|
||||
const ScopeLock protect(mutex);
|
||||
return ServerSocket::Open(error_r);
|
||||
return ServerSocket::Open(error);
|
||||
}
|
||||
|
||||
inline void
|
||||
@@ -91,7 +86,7 @@ HttpdOutput::Unbind()
|
||||
}
|
||||
|
||||
inline bool
|
||||
HttpdOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
HttpdOutput::Configure(const config_param ¶m, Error &error)
|
||||
{
|
||||
/* read configuration */
|
||||
name = param.GetBlockValue("name", "Set name in config");
|
||||
@@ -104,8 +99,8 @@ HttpdOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
param.GetBlockValue("encoder", "vorbis");
|
||||
const auto encoder_plugin = encoder_plugin_get(encoder_name);
|
||||
if (encoder_plugin == NULL) {
|
||||
g_set_error(error_r, httpd_output_quark(), 0,
|
||||
"No such encoder: %s", encoder_name);
|
||||
error.Format(httpd_output_domain,
|
||||
"No such encoder: %s", encoder_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -116,14 +111,14 @@ HttpdOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
const char *bind_to_address = param.GetBlockValue("bind_to_address");
|
||||
bool success = bind_to_address != NULL &&
|
||||
strcmp(bind_to_address, "any") != 0
|
||||
? AddHost(bind_to_address, port, error_r)
|
||||
: AddPort(port, error_r);
|
||||
? AddHost(bind_to_address, port, error)
|
||||
: AddPort(port, error);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
/* initialize encoder */
|
||||
|
||||
encoder = encoder_init(*encoder_plugin, param, error_r);
|
||||
encoder = encoder_init(*encoder_plugin, param, error);
|
||||
if (encoder == nullptr)
|
||||
return false;
|
||||
|
||||
@@ -136,18 +131,17 @@ HttpdOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
httpd_output_init(const struct config_param ¶m,
|
||||
GError **error_r)
|
||||
httpd_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
HttpdOutput *httpd = new HttpdOutput(*main_loop);
|
||||
|
||||
if (!ao_base_init(&httpd->base, &httpd_output_plugin, param,
|
||||
error_r)) {
|
||||
error)) {
|
||||
delete httpd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!httpd->Configure(param, error_r)) {
|
||||
if (!httpd->Configure(param, error)) {
|
||||
ao_base_finish(&httpd->base);
|
||||
delete httpd;
|
||||
return nullptr;
|
||||
@@ -205,7 +199,8 @@ HttpdOutput::OnAccept(int fd, const sockaddr &address,
|
||||
|
||||
#ifdef HAVE_LIBWRAP
|
||||
if (address.sa_family != AF_UNIX) {
|
||||
char *hostaddr = sockaddr_to_string(&address, address_length, NULL);
|
||||
char *hostaddr = sockaddr_to_string(&address, address_length,
|
||||
IgnoreError());
|
||||
const char *progname = g_get_prgname();
|
||||
|
||||
struct request_info req;
|
||||
@@ -249,7 +244,7 @@ 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, NULL);
|
||||
encoder_flush(encoder, IgnoreError());
|
||||
unflushed_input = 0;
|
||||
}
|
||||
|
||||
@@ -273,11 +268,11 @@ HttpdOutput::ReadPage()
|
||||
}
|
||||
|
||||
static bool
|
||||
httpd_output_enable(struct audio_output *ao, GError **error_r)
|
||||
httpd_output_enable(struct audio_output *ao, Error &error)
|
||||
{
|
||||
HttpdOutput *httpd = Cast(ao);
|
||||
|
||||
return httpd->Bind(error_r);
|
||||
return httpd->Bind(error);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -289,7 +284,7 @@ httpd_output_disable(struct audio_output *ao)
|
||||
}
|
||||
|
||||
inline bool
|
||||
HttpdOutput::OpenEncoder(AudioFormat &audio_format, GError **error)
|
||||
HttpdOutput::OpenEncoder(AudioFormat &audio_format, Error &error)
|
||||
{
|
||||
if (!encoder_open(encoder, audio_format, error))
|
||||
return false;
|
||||
@@ -305,14 +300,14 @@ HttpdOutput::OpenEncoder(AudioFormat &audio_format, GError **error)
|
||||
}
|
||||
|
||||
inline bool
|
||||
HttpdOutput::Open(AudioFormat &audio_format, GError **error_r)
|
||||
HttpdOutput::Open(AudioFormat &audio_format, Error &error)
|
||||
{
|
||||
assert(!open);
|
||||
assert(clients.empty());
|
||||
|
||||
/* open the encoder */
|
||||
|
||||
if (!OpenEncoder(audio_format, error_r))
|
||||
if (!OpenEncoder(audio_format, error))
|
||||
return false;
|
||||
|
||||
/* initialize other attributes */
|
||||
@@ -327,7 +322,7 @@ HttpdOutput::Open(AudioFormat &audio_format, GError **error_r)
|
||||
|
||||
static bool
|
||||
httpd_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
HttpdOutput *httpd = Cast(ao);
|
||||
|
||||
@@ -439,9 +434,9 @@ HttpdOutput::BroadcastFromEncoder()
|
||||
}
|
||||
|
||||
inline bool
|
||||
HttpdOutput::EncodeAndPlay(const void *chunk, size_t size, GError **error_r)
|
||||
HttpdOutput::EncodeAndPlay(const void *chunk, size_t size, Error &error)
|
||||
{
|
||||
if (!encoder_write(encoder, chunk, size, error_r))
|
||||
if (!encoder_write(encoder, chunk, size, error))
|
||||
return false;
|
||||
|
||||
unflushed_input += size;
|
||||
@@ -452,12 +447,12 @@ HttpdOutput::EncodeAndPlay(const void *chunk, size_t size, GError **error_r)
|
||||
|
||||
static size_t
|
||||
httpd_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
HttpdOutput *httpd = Cast(ao);
|
||||
|
||||
if (httpd->LockHasClients()) {
|
||||
if (!httpd->EncodeAndPlay(chunk, size, error_r))
|
||||
if (!httpd->EncodeAndPlay(chunk, size, error))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -476,7 +471,7 @@ httpd_output_pause(struct audio_output *ao)
|
||||
if (httpd->LockHasClients()) {
|
||||
static const char silence[1020] = { 0 };
|
||||
return httpd_output_play(ao, silence, sizeof(silence),
|
||||
NULL) > 0;
|
||||
IgnoreError()) > 0;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
@@ -492,13 +487,13 @@ HttpdOutput::SendTag(const Tag *tag)
|
||||
|
||||
/* flush the current stream, and end it */
|
||||
|
||||
encoder_pre_tag(encoder, NULL);
|
||||
encoder_pre_tag(encoder, IgnoreError());
|
||||
BroadcastFromEncoder();
|
||||
|
||||
/* send the tag to the encoder - which starts a new
|
||||
stream now */
|
||||
|
||||
encoder_tag(encoder, tag, NULL);
|
||||
encoder_tag(encoder, tag, IgnoreError());
|
||||
|
||||
/* the first page generated by the encoder will now be
|
||||
used as the new "header" page, which is sent to all
|
||||
|
@@ -20,6 +20,9 @@
|
||||
#include "config.h"
|
||||
#include "JackOutputPlugin.hxx"
|
||||
#include "OutputAPI.hxx"
|
||||
#include "ConfigError.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -82,7 +85,7 @@ struct JackOutput {
|
||||
*/
|
||||
bool pause;
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||
return ao_base_init(&base, &jack_output_plugin, param,
|
||||
error_r);
|
||||
}
|
||||
@@ -92,14 +95,7 @@ struct JackOutput {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
jack_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("jack_output");
|
||||
}
|
||||
static constexpr Domain jack_output_domain("jack_output");
|
||||
|
||||
/**
|
||||
* Determine the number of frames guaranteed to be available on all
|
||||
@@ -250,7 +246,7 @@ mpd_jack_disconnect(JackOutput *jd)
|
||||
* (e.g. register callbacks).
|
||||
*/
|
||||
static bool
|
||||
mpd_jack_connect(JackOutput *jd, GError **error_r)
|
||||
mpd_jack_connect(JackOutput *jd, Error &error)
|
||||
{
|
||||
jack_status_t status;
|
||||
|
||||
@@ -261,9 +257,9 @@ mpd_jack_connect(JackOutput *jd, GError **error_r)
|
||||
jd->client = jack_client_open(jd->name, jd->options, &status,
|
||||
jd->server_name);
|
||||
if (jd->client == nullptr) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"Failed to connect to JACK server, status=%d",
|
||||
status);
|
||||
error.Format(jack_output_domain, status,
|
||||
"Failed to connect to JACK server, status=%d",
|
||||
status);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -276,9 +272,9 @@ mpd_jack_connect(JackOutput *jd, GError **error_r)
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
if (jd->ports[i] == nullptr) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"Cannot register output port \"%s\"",
|
||||
jd->source_ports[i]);
|
||||
error.Format(jack_output_domain,
|
||||
"Cannot register output port \"%s\"",
|
||||
jd->source_ports[i]);
|
||||
mpd_jack_disconnect(jd);
|
||||
return false;
|
||||
}
|
||||
@@ -294,16 +290,16 @@ mpd_jack_test_default_device(void)
|
||||
}
|
||||
|
||||
static unsigned
|
||||
parse_port_list(int line, const char *source, char **dest, GError **error_r)
|
||||
parse_port_list(int line, const char *source, char **dest, Error &error)
|
||||
{
|
||||
char **list = g_strsplit(source, ",", 0);
|
||||
unsigned n = 0;
|
||||
|
||||
for (n = 0; list[n] != nullptr; ++n) {
|
||||
if (n >= MAX_PORTS) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"too many port names in line %d",
|
||||
line);
|
||||
error.Format(config_domain,
|
||||
"too many port names in line %d",
|
||||
line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -313,9 +309,9 @@ parse_port_list(int line, const char *source, char **dest, GError **error_r)
|
||||
g_free(list);
|
||||
|
||||
if (n == 0) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"at least one port name expected in line %d",
|
||||
line);
|
||||
error.Format(config_domain,
|
||||
"at least one port name expected in line %d",
|
||||
line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -323,11 +319,11 @@ parse_port_list(int line, const char *source, char **dest, GError **error_r)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
mpd_jack_init(const config_param ¶m, GError **error_r)
|
||||
mpd_jack_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
JackOutput *jd = new JackOutput();
|
||||
|
||||
if (!jd->Initialize(param, error_r)) {
|
||||
if (!jd->Initialize(param, error)) {
|
||||
delete jd;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -355,7 +351,7 @@ mpd_jack_init(const config_param ¶m, GError **error_r)
|
||||
|
||||
value = param.GetBlockValue("source_ports", "left,right");
|
||||
jd->num_source_ports = parse_port_list(param.line, value,
|
||||
jd->source_ports, error_r);
|
||||
jd->source_ports, error);
|
||||
if (jd->num_source_ports == 0)
|
||||
return nullptr;
|
||||
|
||||
@@ -373,7 +369,7 @@ mpd_jack_init(const config_param ¶m, GError **error_r)
|
||||
if (value != nullptr) {
|
||||
jd->num_destination_ports =
|
||||
parse_port_list(param.line, value,
|
||||
jd->destination_ports, error_r);
|
||||
jd->destination_ports, error);
|
||||
if (jd->num_destination_ports == 0)
|
||||
return nullptr;
|
||||
} else {
|
||||
@@ -414,14 +410,14 @@ mpd_jack_finish(struct audio_output *ao)
|
||||
}
|
||||
|
||||
static bool
|
||||
mpd_jack_enable(struct audio_output *ao, GError **error_r)
|
||||
mpd_jack_enable(struct audio_output *ao, Error &error)
|
||||
{
|
||||
JackOutput *jd = (JackOutput *)ao;
|
||||
|
||||
for (unsigned i = 0; i < jd->num_source_ports; ++i)
|
||||
jd->ringbuffer[i] = nullptr;
|
||||
|
||||
return mpd_jack_connect(jd, error_r);
|
||||
return mpd_jack_connect(jd, error);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -460,7 +456,7 @@ mpd_jack_stop(JackOutput *jd)
|
||||
}
|
||||
|
||||
static bool
|
||||
mpd_jack_start(JackOutput *jd, GError **error_r)
|
||||
mpd_jack_start(JackOutput *jd, Error &error)
|
||||
{
|
||||
const char *destination_ports[MAX_PORTS], **jports;
|
||||
const char *duplicate_port = nullptr;
|
||||
@@ -484,8 +480,7 @@ mpd_jack_start(JackOutput *jd, GError **error_r)
|
||||
}
|
||||
|
||||
if ( jack_activate(jd->client) ) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"cannot activate client");
|
||||
error.Set(jack_output_domain, "cannot activate client");
|
||||
mpd_jack_stop(jd);
|
||||
return false;
|
||||
}
|
||||
@@ -496,8 +491,7 @@ mpd_jack_start(JackOutput *jd, GError **error_r)
|
||||
jports = jack_get_ports(jd->client, nullptr, nullptr,
|
||||
JackPortIsPhysical | JackPortIsInput);
|
||||
if (jports == nullptr) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"no ports found");
|
||||
error.Set(jack_output_domain, "no ports found");
|
||||
mpd_jack_stop(jd);
|
||||
return false;
|
||||
}
|
||||
@@ -551,9 +545,9 @@ mpd_jack_start(JackOutput *jd, GError **error_r)
|
||||
ret = jack_connect(jd->client, jack_port_name(jd->ports[i]),
|
||||
destination_ports[i]);
|
||||
if (ret != 0) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"Not a valid JACK port: %s",
|
||||
destination_ports[i]);
|
||||
error.Format(jack_output_domain,
|
||||
"Not a valid JACK port: %s",
|
||||
destination_ports[i]);
|
||||
|
||||
if (jports != nullptr)
|
||||
free(jports);
|
||||
@@ -571,9 +565,9 @@ mpd_jack_start(JackOutput *jd, GError **error_r)
|
||||
ret = jack_connect(jd->client, jack_port_name(jd->ports[0]),
|
||||
duplicate_port);
|
||||
if (ret != 0) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"Not a valid JACK port: %s",
|
||||
duplicate_port);
|
||||
error.Format(jack_output_domain,
|
||||
"Not a valid JACK port: %s",
|
||||
duplicate_port);
|
||||
|
||||
if (jports != nullptr)
|
||||
free(jports);
|
||||
@@ -591,7 +585,7 @@ mpd_jack_start(JackOutput *jd, GError **error_r)
|
||||
|
||||
static bool
|
||||
mpd_jack_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
JackOutput *jd = (JackOutput *)ao;
|
||||
|
||||
@@ -602,13 +596,13 @@ mpd_jack_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
if (jd->client != nullptr && jd->shutdown)
|
||||
mpd_jack_disconnect(jd);
|
||||
|
||||
if (jd->client == nullptr && !mpd_jack_connect(jd, error_r))
|
||||
if (jd->client == nullptr && !mpd_jack_connect(jd, error))
|
||||
return false;
|
||||
|
||||
set_audioformat(jd, audio_format);
|
||||
jd->audio_format = audio_format;
|
||||
|
||||
if (!mpd_jack_start(jd, error_r))
|
||||
if (!mpd_jack_start(jd, error))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -701,7 +695,7 @@ mpd_jack_write_samples(JackOutput *jd, const void *src,
|
||||
|
||||
static size_t
|
||||
mpd_jack_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
JackOutput *jd = (JackOutput *)ao;
|
||||
const size_t frame_size = jd->audio_format.GetFrameSize();
|
||||
@@ -714,9 +708,9 @@ mpd_jack_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
|
||||
while (true) {
|
||||
if (jd->shutdown) {
|
||||
g_set_error(error_r, jack_output_quark(), 0,
|
||||
"Refusing to play, because "
|
||||
"there is no client thread");
|
||||
error.Set(jack_output_domain,
|
||||
"Refusing to play, because "
|
||||
"there is no client thread");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -31,9 +31,9 @@ struct NullOutput {
|
||||
|
||||
Timer *timer;
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error) {
|
||||
return ao_base_init(&base, &null_output_plugin, param,
|
||||
error_r);
|
||||
error);
|
||||
}
|
||||
|
||||
void Deinitialize() {
|
||||
@@ -42,11 +42,11 @@ struct NullOutput {
|
||||
};
|
||||
|
||||
static struct audio_output *
|
||||
null_init(const config_param ¶m, GError **error_r)
|
||||
null_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
NullOutput *nd = new NullOutput();
|
||||
|
||||
if (!nd->Initialize(param, error_r)) {
|
||||
if (!nd->Initialize(param, error)) {
|
||||
delete nd;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ null_finish(struct audio_output *ao)
|
||||
|
||||
static bool
|
||||
null_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
gcc_unused GError **error)
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
NullOutput *nd = (NullOutput *)ao;
|
||||
|
||||
@@ -98,7 +98,7 @@ null_delay(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
null_play(struct audio_output *ao, gcc_unused const void *chunk, size_t size,
|
||||
gcc_unused GError **error)
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
NullOutput *nd = (NullOutput *)ao;
|
||||
Timer *timer = nd->timer;
|
||||
|
@@ -21,6 +21,8 @@
|
||||
#include "OSXOutputPlugin.hxx"
|
||||
#include "OutputAPI.hxx"
|
||||
#include "util/fifo_buffer.h"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "thread/Cond.hxx"
|
||||
|
||||
@@ -47,14 +49,7 @@ struct OSXOutput {
|
||||
struct fifo_buffer *buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
osx_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("osx_output");
|
||||
}
|
||||
static constexpr Domain osx_output_domain("osx_output");
|
||||
|
||||
static bool
|
||||
osx_output_test_default_device(void)
|
||||
@@ -85,10 +80,10 @@ osx_output_configure(OSXOutput *oo, const config_param ¶m)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
osx_output_init(const config_param ¶m, GError **error_r)
|
||||
osx_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
OSXOutput *oo = new OSXOutput();
|
||||
if (!ao_base_init(&oo->base, &osx_output_plugin, param, error_r)) {
|
||||
if (!ao_base_init(&oo->base, &osx_output_plugin, param, error)) {
|
||||
delete oo;
|
||||
return NULL;
|
||||
}
|
||||
@@ -107,7 +102,7 @@ osx_output_finish(struct audio_output *ao)
|
||||
}
|
||||
|
||||
static bool
|
||||
osx_output_set_device(OSXOutput *oo, GError **error)
|
||||
osx_output_set_device(OSXOutput *oo, Error &error)
|
||||
{
|
||||
bool ret = true;
|
||||
OSStatus status;
|
||||
@@ -124,9 +119,9 @@ osx_output_set_device(OSXOutput *oo, GError **error)
|
||||
&size,
|
||||
NULL);
|
||||
if (status != noErr) {
|
||||
g_set_error(error, osx_output_quark(), status,
|
||||
"Unable to determine number of OS X audio devices: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
error.Format(osx_output_domain, status,
|
||||
"Unable to determine number of OS X audio devices: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
@@ -138,9 +133,9 @@ osx_output_set_device(OSXOutput *oo, GError **error)
|
||||
&size,
|
||||
deviceids);
|
||||
if (status != noErr) {
|
||||
g_set_error(error, osx_output_quark(), status,
|
||||
"Unable to determine OS X audio device IDs: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
error.Format(osx_output_domain, status,
|
||||
"Unable to determine OS X audio device IDs: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
@@ -152,11 +147,11 @@ osx_output_set_device(OSXOutput *oo, GError **error)
|
||||
kAudioDevicePropertyDeviceName,
|
||||
&size, name);
|
||||
if (status != noErr) {
|
||||
g_set_error(error, osx_output_quark(), status,
|
||||
"Unable to determine OS X device name "
|
||||
"(device %u): %s",
|
||||
(unsigned int) deviceids[i],
|
||||
GetMacOSStatusCommentString(status));
|
||||
error.Format(osx_output_domain, status,
|
||||
"Unable to determine OS X device name "
|
||||
"(device %u): %s",
|
||||
(unsigned int) deviceids[i],
|
||||
GetMacOSStatusCommentString(status));
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
@@ -180,9 +175,9 @@ osx_output_set_device(OSXOutput *oo, GError **error)
|
||||
&(deviceids[i]),
|
||||
sizeof(AudioDeviceID));
|
||||
if (status != noErr) {
|
||||
g_set_error(error, osx_output_quark(), status,
|
||||
"Unable to set OS X audio output device: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
error.Format(osx_output_domain, status,
|
||||
"Unable to set OS X audio output device: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
@@ -237,7 +232,7 @@ osx_render(void *vdata,
|
||||
}
|
||||
|
||||
static bool
|
||||
osx_output_enable(struct audio_output *ao, GError **error_r)
|
||||
osx_output_enable(struct audio_output *ao, Error &error)
|
||||
{
|
||||
OSXOutput *oo = (OSXOutput *)ao;
|
||||
|
||||
@@ -250,20 +245,20 @@ osx_output_enable(struct audio_output *ao, GError **error_r)
|
||||
|
||||
Component comp = FindNextComponent(NULL, &desc);
|
||||
if (comp == 0) {
|
||||
g_set_error(error_r, osx_output_quark(), 0,
|
||||
"Error finding OS X component");
|
||||
error.Set(osx_output_domain,
|
||||
"Error finding OS X component");
|
||||
return false;
|
||||
}
|
||||
|
||||
OSStatus status = OpenAComponent(comp, &oo->au);
|
||||
if (status != noErr) {
|
||||
g_set_error(error_r, osx_output_quark(), status,
|
||||
"Unable to open OS X component: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
error.Format(osx_output_domain, status,
|
||||
"Unable to open OS X component: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!osx_output_set_device(oo, error_r)) {
|
||||
if (!osx_output_set_device(oo, error)) {
|
||||
CloseComponent(oo->au);
|
||||
return false;
|
||||
}
|
||||
@@ -279,8 +274,8 @@ osx_output_enable(struct audio_output *ao, GError **error_r)
|
||||
&callback, sizeof(callback));
|
||||
if (result != noErr) {
|
||||
CloseComponent(oo->au);
|
||||
g_set_error(error_r, osx_output_quark(), result,
|
||||
"unable to set callback for OS X audio unit");
|
||||
error.Set(osx_output_domain, result,
|
||||
"unable to set callback for OS X audio unit");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -316,7 +311,8 @@ osx_output_close(struct audio_output *ao)
|
||||
}
|
||||
|
||||
static bool
|
||||
osx_output_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
|
||||
osx_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
Error &error)
|
||||
{
|
||||
OSXOutput *od = (OSXOutput *)ao;
|
||||
|
||||
@@ -359,16 +355,16 @@ osx_output_open(struct audio_output *ao, AudioFormat &audio_format, GError **err
|
||||
&stream_description,
|
||||
sizeof(stream_description));
|
||||
if (result != noErr) {
|
||||
g_set_error(error, osx_output_quark(), result,
|
||||
"Unable to set format on OS X device");
|
||||
error.Set(osx_output_domain, result,
|
||||
"Unable to set format on OS X device");
|
||||
return false;
|
||||
}
|
||||
|
||||
OSStatus status = AudioUnitInitialize(od->au);
|
||||
if (status != noErr) {
|
||||
g_set_error(error, osx_output_quark(), status,
|
||||
"Unable to initialize OS X audio unit: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
error.Set(osx_output_domain, status,
|
||||
"Unable to initialize OS X audio unit: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -379,9 +375,9 @@ osx_output_open(struct audio_output *ao, AudioFormat &audio_format, GError **err
|
||||
status = AudioOutputUnitStart(od->au);
|
||||
if (status != 0) {
|
||||
AudioUnitUninitialize(od->au);
|
||||
g_set_error(error, osx_output_quark(), status,
|
||||
"unable to start audio output: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
error.Format(osx_output_domain, status,
|
||||
"unable to start audio output: %s",
|
||||
GetMacOSStatusCommentString(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -390,7 +386,7 @@ osx_output_open(struct audio_output *ao, AudioFormat &audio_format, GError **err
|
||||
|
||||
static size_t
|
||||
osx_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
gcc_unused GError **error)
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
OSXOutput *od = (OSXOutput *)ao;
|
||||
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#include "config.h"
|
||||
#include "OpenALOutputPlugin.hxx"
|
||||
#include "OutputAPI.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@@ -49,7 +51,7 @@ struct OpenALOutput {
|
||||
ALenum format;
|
||||
ALuint frequency;
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||
return ao_base_init(&base, &openal_output_plugin, param,
|
||||
error_r);
|
||||
}
|
||||
@@ -59,12 +61,7 @@ struct OpenALOutput {
|
||||
}
|
||||
};
|
||||
|
||||
gcc_const
|
||||
static inline GQuark
|
||||
openal_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("openal_output");
|
||||
}
|
||||
static constexpr Domain openal_output_domain("openal_output");
|
||||
|
||||
static ALenum
|
||||
openal_audio_format(AudioFormat &audio_format)
|
||||
@@ -115,24 +112,23 @@ openal_is_playing(const OpenALOutput *od)
|
||||
}
|
||||
|
||||
static bool
|
||||
openal_setup_context(OpenALOutput *od,
|
||||
GError **error)
|
||||
openal_setup_context(OpenALOutput *od, Error &error)
|
||||
{
|
||||
od->device = alcOpenDevice(od->device_name);
|
||||
|
||||
if (od->device == nullptr) {
|
||||
g_set_error(error, openal_output_quark(), 0,
|
||||
"Error opening OpenAL device \"%s\"\n",
|
||||
od->device_name);
|
||||
error.Format(openal_output_domain,
|
||||
"Error opening OpenAL device \"%s\"",
|
||||
od->device_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
od->context = alcCreateContext(od->device, nullptr);
|
||||
|
||||
if (od->context == nullptr) {
|
||||
g_set_error(error, openal_output_quark(), 0,
|
||||
"Error creating context for \"%s\"\n",
|
||||
od->device_name);
|
||||
error.Format(openal_output_domain,
|
||||
"Error creating context for \"%s\"",
|
||||
od->device_name);
|
||||
alcCloseDevice(od->device);
|
||||
return false;
|
||||
}
|
||||
@@ -141,7 +137,7 @@ openal_setup_context(OpenALOutput *od,
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
openal_init(const config_param ¶m, GError **error_r)
|
||||
openal_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
const char *device_name = param.GetBlockValue("device");
|
||||
if (device_name == nullptr) {
|
||||
@@ -149,7 +145,7 @@ openal_init(const config_param ¶m, GError **error_r)
|
||||
}
|
||||
|
||||
OpenALOutput *od = new OpenALOutput();
|
||||
if (!od->Initialize(param, error_r)) {
|
||||
if (!od->Initialize(param, error)) {
|
||||
delete od;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -170,7 +166,7 @@ openal_finish(struct audio_output *ao)
|
||||
|
||||
static bool
|
||||
openal_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
OpenALOutput *od = (OpenALOutput *)ao;
|
||||
|
||||
@@ -184,16 +180,14 @@ openal_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
alGenBuffers(NUM_BUFFERS, od->buffers);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
g_set_error(error, openal_output_quark(), 0,
|
||||
"Failed to generate buffers");
|
||||
error.Set(openal_output_domain, "Failed to generate buffers");
|
||||
return false;
|
||||
}
|
||||
|
||||
alGenSources(1, &od->source);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
g_set_error(error, openal_output_quark(), 0,
|
||||
"Failed to generate source");
|
||||
error.Set(openal_output_domain, "Failed to generate source");
|
||||
alDeleteBuffers(NUM_BUFFERS, od->buffers);
|
||||
return false;
|
||||
}
|
||||
@@ -231,7 +225,7 @@ openal_delay(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
openal_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
gcc_unused GError **error)
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
OpenALOutput *od = (OpenALOutput *)ao;
|
||||
ALuint buffer;
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include "OutputAPI.hxx"
|
||||
#include "MixerList.hxx"
|
||||
#include "system/fd_util.h"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@@ -80,7 +82,7 @@ struct OssOutput {
|
||||
|
||||
OssOutput():fd(-1), device(nullptr) {}
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||
return ao_base_init(&base, &oss_output_plugin, param,
|
||||
error_r);
|
||||
}
|
||||
@@ -90,14 +92,7 @@ struct OssOutput {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
oss_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("oss_output");
|
||||
}
|
||||
static constexpr Domain oss_output_domain("oss_output");
|
||||
|
||||
enum oss_stat {
|
||||
OSS_STAT_NO_ERROR = 0,
|
||||
@@ -155,7 +150,7 @@ oss_output_test_default_device(void)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
oss_open_default(GError **error)
|
||||
oss_open_default(Error &error)
|
||||
{
|
||||
int err[G_N_ELEMENTS(default_devices)];
|
||||
enum oss_stat ret[G_N_ELEMENTS(default_devices)];
|
||||
@@ -196,18 +191,18 @@ oss_open_default(GError **error)
|
||||
}
|
||||
}
|
||||
|
||||
g_set_error(error, oss_output_quark(), 0,
|
||||
"error trying to open default OSS device");
|
||||
error.Set(oss_output_domain,
|
||||
"error trying to open default OSS device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
oss_output_init(const config_param ¶m, GError **error_r)
|
||||
oss_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
const char *device = param.GetBlockValue("device");
|
||||
if (device != NULL) {
|
||||
OssOutput *od = new OssOutput();
|
||||
if (!od->Initialize(param, error_r)) {
|
||||
if (!od->Initialize(param, error)) {
|
||||
delete od;
|
||||
return NULL;
|
||||
}
|
||||
@@ -216,7 +211,7 @@ oss_output_init(const config_param ¶m, GError **error_r)
|
||||
return &od->base;
|
||||
}
|
||||
|
||||
return oss_open_default(error_r);
|
||||
return oss_open_default(error);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -231,7 +226,7 @@ oss_output_finish(struct audio_output *ao)
|
||||
#ifdef AFMT_S24_PACKED
|
||||
|
||||
static bool
|
||||
oss_output_enable(struct audio_output *ao, gcc_unused GError **error_r)
|
||||
oss_output_enable(struct audio_output *ao, gcc_unused Error &error)
|
||||
{
|
||||
OssOutput *od = (OssOutput *)ao;
|
||||
|
||||
@@ -269,16 +264,16 @@ enum oss_setup_result {
|
||||
/**
|
||||
* Invoke an ioctl on the OSS file descriptor. On success, SUCCESS is
|
||||
* returned. If the parameter is not supported, UNSUPPORTED is
|
||||
* returned. Any other failure returns ERROR and allocates a GError.
|
||||
* returned. Any other failure returns ERROR and allocates an #Error.
|
||||
*/
|
||||
static enum oss_setup_result
|
||||
oss_try_ioctl_r(int fd, unsigned long request, int *value_r,
|
||||
const char *msg, GError **error_r)
|
||||
const char *msg, Error &error)
|
||||
{
|
||||
assert(fd >= 0);
|
||||
assert(value_r != NULL);
|
||||
assert(msg != NULL);
|
||||
assert(error_r == NULL || *error_r == NULL);
|
||||
assert(!error.IsDefined());
|
||||
|
||||
int ret = ioctl(fd, request, value_r);
|
||||
if (ret >= 0)
|
||||
@@ -287,19 +282,18 @@ oss_try_ioctl_r(int fd, unsigned long request, int *value_r,
|
||||
if (errno == EINVAL)
|
||||
return UNSUPPORTED;
|
||||
|
||||
g_set_error(error_r, oss_output_quark(), errno,
|
||||
"%s: %s", msg, g_strerror(errno));
|
||||
error.SetErrno(msg);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke an ioctl on the OSS file descriptor. On success, SUCCESS is
|
||||
* returned. If the parameter is not supported, UNSUPPORTED is
|
||||
* returned. Any other failure returns ERROR and allocates a GError.
|
||||
* returned. Any other failure returns ERROR and allocates an #Error.
|
||||
*/
|
||||
static enum oss_setup_result
|
||||
oss_try_ioctl(int fd, unsigned long request, int value,
|
||||
const char *msg, GError **error_r)
|
||||
const char *msg, Error &error_r)
|
||||
{
|
||||
return oss_try_ioctl_r(fd, request, &value, msg, error_r);
|
||||
}
|
||||
@@ -309,12 +303,12 @@ oss_try_ioctl(int fd, unsigned long request, int value,
|
||||
* specified number is not supported.
|
||||
*/
|
||||
static bool
|
||||
oss_setup_channels(int fd, AudioFormat &audio_format, GError **error_r)
|
||||
oss_setup_channels(int fd, AudioFormat &audio_format, Error &error)
|
||||
{
|
||||
const char *const msg = "Failed to set channel count";
|
||||
int channels = audio_format.channels;
|
||||
enum oss_setup_result result =
|
||||
oss_try_ioctl_r(fd, SNDCTL_DSP_CHANNELS, &channels, msg, error_r);
|
||||
oss_try_ioctl_r(fd, SNDCTL_DSP_CHANNELS, &channels, msg, error);
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
if (!audio_valid_channel_count(channels))
|
||||
@@ -337,7 +331,7 @@ oss_setup_channels(int fd, AudioFormat &audio_format, GError **error_r)
|
||||
|
||||
channels = i;
|
||||
result = oss_try_ioctl_r(fd, SNDCTL_DSP_CHANNELS, &channels,
|
||||
msg, error_r);
|
||||
msg, error);
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
if (!audio_valid_channel_count(channels))
|
||||
@@ -354,7 +348,7 @@ oss_setup_channels(int fd, AudioFormat &audio_format, GError **error_r)
|
||||
}
|
||||
}
|
||||
|
||||
g_set_error(error_r, oss_output_quark(), EINVAL, "%s", msg);
|
||||
error.Set(oss_output_domain, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -364,13 +358,13 @@ oss_setup_channels(int fd, AudioFormat &audio_format, GError **error_r)
|
||||
*/
|
||||
static bool
|
||||
oss_setup_sample_rate(int fd, AudioFormat &audio_format,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
const char *const msg = "Failed to set sample rate";
|
||||
int sample_rate = audio_format.sample_rate;
|
||||
enum oss_setup_result result =
|
||||
oss_try_ioctl_r(fd, SNDCTL_DSP_SPEED, &sample_rate,
|
||||
msg, error_r);
|
||||
msg, error);
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
if (!audio_valid_sample_rate(sample_rate))
|
||||
@@ -393,7 +387,7 @@ oss_setup_sample_rate(int fd, AudioFormat &audio_format,
|
||||
continue;
|
||||
|
||||
result = oss_try_ioctl_r(fd, SNDCTL_DSP_SPEED, &sample_rate,
|
||||
msg, error_r);
|
||||
msg, error);
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
if (!audio_valid_sample_rate(sample_rate))
|
||||
@@ -410,7 +404,7 @@ oss_setup_sample_rate(int fd, AudioFormat &audio_format,
|
||||
}
|
||||
}
|
||||
|
||||
g_set_error(error_r, oss_output_quark(), EINVAL, "%s", msg);
|
||||
error.Set(oss_output_domain, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -498,7 +492,7 @@ oss_probe_sample_format(int fd, SampleFormat sample_format,
|
||||
#ifdef AFMT_S24_PACKED
|
||||
PcmExport &pcm_export,
|
||||
#endif
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
int oss_format = sample_format_to_oss(sample_format);
|
||||
if (oss_format == AFMT_QUERY)
|
||||
@@ -507,7 +501,7 @@ oss_probe_sample_format(int fd, SampleFormat sample_format,
|
||||
enum oss_setup_result result =
|
||||
oss_try_ioctl_r(fd, SNDCTL_DSP_SAMPLESIZE,
|
||||
&oss_format,
|
||||
"Failed to set sample format", error_r);
|
||||
"Failed to set sample format", error);
|
||||
|
||||
#ifdef AFMT_S24_PACKED
|
||||
if (result == UNSUPPORTED && sample_format == SampleFormat::S24_P32) {
|
||||
@@ -516,7 +510,7 @@ oss_probe_sample_format(int fd, SampleFormat sample_format,
|
||||
oss_format = AFMT_S24_PACKED;
|
||||
result = oss_try_ioctl_r(fd, SNDCTL_DSP_SAMPLESIZE,
|
||||
&oss_format,
|
||||
"Failed to set sample format", error_r);
|
||||
"Failed to set sample format", error);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -550,7 +544,7 @@ oss_setup_sample_format(int fd, AudioFormat &audio_format,
|
||||
#ifdef AFMT_S24_PACKED
|
||||
PcmExport &pcm_export,
|
||||
#endif
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
SampleFormat mpd_format;
|
||||
enum oss_setup_result result =
|
||||
@@ -559,7 +553,7 @@ oss_setup_sample_format(int fd, AudioFormat &audio_format,
|
||||
#ifdef AFMT_S24_PACKED
|
||||
pcm_export,
|
||||
#endif
|
||||
error_r);
|
||||
error);
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
audio_format.format = mpd_format;
|
||||
@@ -597,7 +591,7 @@ oss_setup_sample_format(int fd, AudioFormat &audio_format,
|
||||
#ifdef AFMT_S24_PACKED
|
||||
pcm_export,
|
||||
#endif
|
||||
error_r);
|
||||
error);
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
audio_format.format = mpd_format;
|
||||
@@ -611,8 +605,7 @@ oss_setup_sample_format(int fd, AudioFormat &audio_format,
|
||||
}
|
||||
}
|
||||
|
||||
g_set_error_literal(error_r, oss_output_quark(), EINVAL,
|
||||
"Failed to set sample format");
|
||||
error.Set(oss_output_domain, "Failed to set sample format");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -621,30 +614,29 @@ oss_setup_sample_format(int fd, AudioFormat &audio_format,
|
||||
*/
|
||||
static bool
|
||||
oss_setup(OssOutput *od, AudioFormat &audio_format,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
return oss_setup_channels(od->fd, audio_format, error_r) &&
|
||||
oss_setup_sample_rate(od->fd, audio_format, error_r) &&
|
||||
return oss_setup_channels(od->fd, audio_format, error) &&
|
||||
oss_setup_sample_rate(od->fd, audio_format, error) &&
|
||||
oss_setup_sample_format(od->fd, audio_format, &od->oss_format,
|
||||
#ifdef AFMT_S24_PACKED
|
||||
od->pcm_export,
|
||||
#endif
|
||||
error_r);
|
||||
error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reopen the device with the saved audio_format, without any probing.
|
||||
*/
|
||||
static bool
|
||||
oss_reopen(OssOutput *od, GError **error_r)
|
||||
oss_reopen(OssOutput *od, Error &error)
|
||||
{
|
||||
assert(od->fd < 0);
|
||||
|
||||
od->fd = open_cloexec(od->device, O_WRONLY, 0);
|
||||
if (od->fd < 0) {
|
||||
g_set_error(error_r, oss_output_quark(), errno,
|
||||
"Error opening OSS device \"%s\": %s",
|
||||
od->device, g_strerror(errno));
|
||||
error.FormatErrno("Error opening OSS device \"%s\"",
|
||||
od->device);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -652,35 +644,32 @@ oss_reopen(OssOutput *od, GError **error_r)
|
||||
|
||||
const char *const msg1 = "Failed to set channel count";
|
||||
result = oss_try_ioctl(od->fd, SNDCTL_DSP_CHANNELS,
|
||||
od->audio_format.channels, msg1, error_r);
|
||||
od->audio_format.channels, msg1, error);
|
||||
if (result != SUCCESS) {
|
||||
oss_close(od);
|
||||
if (result == UNSUPPORTED)
|
||||
g_set_error(error_r, oss_output_quark(), EINVAL,
|
||||
"%s", msg1);
|
||||
error.Set(oss_output_domain, msg1);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *const msg2 = "Failed to set sample rate";
|
||||
result = oss_try_ioctl(od->fd, SNDCTL_DSP_SPEED,
|
||||
od->audio_format.sample_rate, msg2, error_r);
|
||||
od->audio_format.sample_rate, msg2, error);
|
||||
if (result != SUCCESS) {
|
||||
oss_close(od);
|
||||
if (result == UNSUPPORTED)
|
||||
g_set_error(error_r, oss_output_quark(), EINVAL,
|
||||
"%s", msg2);
|
||||
error.Set(oss_output_domain, msg2);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *const msg3 = "Failed to set sample format";
|
||||
result = oss_try_ioctl(od->fd, SNDCTL_DSP_SAMPLESIZE,
|
||||
od->oss_format,
|
||||
msg3, error_r);
|
||||
msg3, error);
|
||||
if (result != SUCCESS) {
|
||||
oss_close(od);
|
||||
if (result == UNSUPPORTED)
|
||||
g_set_error(error_r, oss_output_quark(), EINVAL,
|
||||
"%s", msg3);
|
||||
error.Set(oss_output_domain, msg3);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -689,15 +678,14 @@ oss_reopen(OssOutput *od, GError **error_r)
|
||||
|
||||
static bool
|
||||
oss_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
OssOutput *od = (OssOutput *)ao;
|
||||
|
||||
od->fd = open_cloexec(od->device, O_WRONLY, 0);
|
||||
if (od->fd < 0) {
|
||||
g_set_error(error, oss_output_quark(), errno,
|
||||
"Error opening OSS device \"%s\": %s",
|
||||
od->device, g_strerror(errno));
|
||||
error.FormatErrno("Error opening OSS device \"%s\"",
|
||||
od->device);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -731,7 +719,7 @@ oss_output_cancel(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
OssOutput *od = (OssOutput *)ao;
|
||||
ssize_t ret;
|
||||
@@ -754,9 +742,7 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
}
|
||||
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
g_set_error(error, oss_output_quark(), errno,
|
||||
"Write error on %s: %s",
|
||||
od->device, g_strerror(errno));
|
||||
error.FormatErrno("Write error on %s", od->device);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,9 @@
|
||||
#include "config.h"
|
||||
#include "PipeOutputPlugin.hxx"
|
||||
#include "OutputAPI.hxx"
|
||||
#include "ConfigError.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
@@ -30,34 +33,27 @@ struct PipeOutput {
|
||||
char *cmd;
|
||||
FILE *fh;
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error) {
|
||||
return ao_base_init(&base, &pipe_output_plugin, param,
|
||||
error_r);
|
||||
error);
|
||||
}
|
||||
|
||||
void Deinitialize() {
|
||||
ao_base_finish(&base);
|
||||
}
|
||||
|
||||
bool Configure(const config_param ¶m, GError **error_r);
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
pipe_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("pipe_output");
|
||||
}
|
||||
static constexpr Domain pipe_output_domain("pipe_output");
|
||||
|
||||
inline bool
|
||||
PipeOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
PipeOutput::Configure(const config_param ¶m, Error &error)
|
||||
{
|
||||
cmd = param.DupBlockString("command");
|
||||
if (cmd == nullptr) {
|
||||
g_set_error(error_r, pipe_output_quark(), 0,
|
||||
"No \"command\" parameter specified");
|
||||
error.Set(config_domain,
|
||||
"No \"command\" parameter specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -65,16 +61,16 @@ PipeOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
pipe_output_init(const config_param ¶m, GError **error_r)
|
||||
pipe_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
PipeOutput *pd = new PipeOutput();
|
||||
|
||||
if (!pd->Initialize(param, error_r)) {
|
||||
if (!pd->Initialize(param, error)) {
|
||||
delete pd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!pd->Configure(param, error_r)) {
|
||||
if (!pd->Configure(param, error)) {
|
||||
pd->Deinitialize();
|
||||
delete pd;
|
||||
return nullptr;
|
||||
@@ -96,15 +92,14 @@ pipe_output_finish(struct audio_output *ao)
|
||||
static bool
|
||||
pipe_output_open(struct audio_output *ao,
|
||||
gcc_unused AudioFormat &audio_format,
|
||||
gcc_unused GError **error)
|
||||
Error &error)
|
||||
{
|
||||
PipeOutput *pd = (PipeOutput *)ao;
|
||||
|
||||
pd->fh = popen(pd->cmd, "w");
|
||||
if (pd->fh == nullptr) {
|
||||
g_set_error(error, pipe_output_quark(), errno,
|
||||
"Error opening pipe \"%s\": %s",
|
||||
pd->cmd, g_strerror(errno));
|
||||
error.FormatErrno("Error opening pipe \"%s\"",
|
||||
pd->cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,15 +115,15 @@ pipe_output_close(struct audio_output *ao)
|
||||
}
|
||||
|
||||
static size_t
|
||||
pipe_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error)
|
||||
pipe_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
Error &error)
|
||||
{
|
||||
PipeOutput *pd = (PipeOutput *)ao;
|
||||
size_t ret;
|
||||
|
||||
ret = fwrite(chunk, 1, size, pd->fh);
|
||||
if (ret == 0)
|
||||
g_set_error(error, pipe_output_quark(), errno,
|
||||
"Write error on pipe: %s", g_strerror(errno));
|
||||
error.SetErrno("Write error on pipe");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include "OutputAPI.hxx"
|
||||
#include "MixerList.hxx"
|
||||
#include "mixer/PulseMixerPlugin.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@@ -54,13 +56,13 @@ struct PulseOutput {
|
||||
size_t writable;
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
pulse_output_quark(void)
|
||||
static constexpr Domain pulse_output_domain("pulse_output");
|
||||
|
||||
static void
|
||||
SetError(Error &error, pa_context *context, const char *msg)
|
||||
{
|
||||
return g_quark_from_static_string("pulse_output");
|
||||
const int e = pa_context_errno(context);
|
||||
error.Format(pulse_output_domain, e, "%s: %s", msg, pa_strerror(e));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -112,14 +114,14 @@ pulse_output_clear_mixer(PulseOutput *po, gcc_unused PulseMixer *pm)
|
||||
}
|
||||
|
||||
bool
|
||||
pulse_output_set_volume(PulseOutput *po,
|
||||
const struct pa_cvolume *volume, GError **error_r)
|
||||
pulse_output_set_volume(PulseOutput *po, const pa_cvolume *volume,
|
||||
Error &error)
|
||||
{
|
||||
pa_operation *o;
|
||||
|
||||
if (po->context == nullptr || po->stream == nullptr ||
|
||||
pa_stream_get_state(po->stream) != PA_STREAM_READY) {
|
||||
g_set_error(error_r, pulse_output_quark(), 0, "disconnected");
|
||||
error.Set(pulse_output_domain, "disconnected");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -127,9 +129,8 @@ pulse_output_set_volume(PulseOutput *po,
|
||||
pa_stream_get_index(po->stream),
|
||||
volume, nullptr, nullptr);
|
||||
if (o == nullptr) {
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"failed to set PulseAudio volume: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
SetError(error, po->context,
|
||||
"failed to set PulseAudio volume");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -235,19 +236,15 @@ pulse_output_subscribe_cb(pa_context *context,
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
static bool
|
||||
pulse_output_connect(PulseOutput *po, GError **error_r)
|
||||
pulse_output_connect(PulseOutput *po, Error &error)
|
||||
{
|
||||
assert(po != nullptr);
|
||||
assert(po->context != nullptr);
|
||||
|
||||
int error;
|
||||
|
||||
error = pa_context_connect(po->context, po->server,
|
||||
(pa_context_flags_t)0, nullptr);
|
||||
if (error < 0) {
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_context_connect() has failed: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
if (pa_context_connect(po->context, po->server,
|
||||
(pa_context_flags_t)0, nullptr) < 0) {
|
||||
SetError(error, po->context,
|
||||
"pa_context_connect() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -300,7 +297,7 @@ pulse_output_delete_context(PulseOutput *po)
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
static bool
|
||||
pulse_output_setup_context(PulseOutput *po, GError **error_r)
|
||||
pulse_output_setup_context(PulseOutput *po, Error &error)
|
||||
{
|
||||
assert(po != nullptr);
|
||||
assert(po->mainloop != nullptr);
|
||||
@@ -308,8 +305,7 @@ pulse_output_setup_context(PulseOutput *po, GError **error_r)
|
||||
po->context = pa_context_new(pa_threaded_mainloop_get_api(po->mainloop),
|
||||
MPD_PULSE_NAME);
|
||||
if (po->context == nullptr) {
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_context_new() has failed");
|
||||
error.Set(pulse_output_domain, "pa_context_new() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -318,7 +314,7 @@ pulse_output_setup_context(PulseOutput *po, GError **error_r)
|
||||
pa_context_set_subscribe_callback(po->context,
|
||||
pulse_output_subscribe_cb, po);
|
||||
|
||||
if (!pulse_output_connect(po, error_r)) {
|
||||
if (!pulse_output_connect(po, error)) {
|
||||
pulse_output_delete_context(po);
|
||||
return false;
|
||||
}
|
||||
@@ -327,14 +323,14 @@ pulse_output_setup_context(PulseOutput *po, GError **error_r)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
pulse_output_init(const config_param ¶m, GError **error_r)
|
||||
pulse_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
PulseOutput *po;
|
||||
|
||||
g_setenv("PULSE_PROP_media.role", "music", true);
|
||||
|
||||
po = new PulseOutput();
|
||||
if (!ao_base_init(&po->base, &pulse_output_plugin, param, error_r)) {
|
||||
if (!ao_base_init(&po->base, &pulse_output_plugin, param, error)) {
|
||||
delete po;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -361,7 +357,7 @@ pulse_output_finish(struct audio_output *ao)
|
||||
}
|
||||
|
||||
static bool
|
||||
pulse_output_enable(struct audio_output *ao, GError **error_r)
|
||||
pulse_output_enable(struct audio_output *ao, Error &error)
|
||||
{
|
||||
PulseOutput *po = (PulseOutput *)ao;
|
||||
|
||||
@@ -374,8 +370,8 @@ pulse_output_enable(struct audio_output *ao, GError **error_r)
|
||||
if (po->mainloop == nullptr) {
|
||||
g_free(po);
|
||||
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_threaded_mainloop_new() has failed");
|
||||
error.Set(pulse_output_domain,
|
||||
"pa_threaded_mainloop_new() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -386,14 +382,14 @@ pulse_output_enable(struct audio_output *ao, GError **error_r)
|
||||
pa_threaded_mainloop_free(po->mainloop);
|
||||
po->mainloop = nullptr;
|
||||
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_threaded_mainloop_start() has failed");
|
||||
error.Set(pulse_output_domain,
|
||||
"pa_threaded_mainloop_start() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* create the libpulse context and connect it */
|
||||
|
||||
if (!pulse_output_setup_context(po, error_r)) {
|
||||
if (!pulse_output_setup_context(po, error)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
pa_threaded_mainloop_stop(po->mainloop);
|
||||
pa_threaded_mainloop_free(po->mainloop);
|
||||
@@ -429,13 +425,13 @@ pulse_output_disable(struct audio_output *ao)
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
static bool
|
||||
pulse_output_wait_connection(PulseOutput *po, GError **error_r)
|
||||
pulse_output_wait_connection(PulseOutput *po, Error &error)
|
||||
{
|
||||
assert(po->mainloop != nullptr);
|
||||
|
||||
pa_context_state_t state;
|
||||
|
||||
if (po->context == nullptr && !pulse_output_setup_context(po, error_r))
|
||||
if (po->context == nullptr && !pulse_output_setup_context(po, error))
|
||||
return false;
|
||||
|
||||
while (true) {
|
||||
@@ -449,9 +445,7 @@ pulse_output_wait_connection(PulseOutput *po, GError **error_r)
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
case PA_CONTEXT_FAILED:
|
||||
/* failure */
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"failed to connect: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
SetError(error, po->context, "failed to connect");
|
||||
pulse_output_delete_context(po);
|
||||
return false;
|
||||
|
||||
@@ -530,16 +524,14 @@ pulse_output_stream_write_cb(gcc_unused pa_stream *stream, size_t nbytes,
|
||||
*/
|
||||
static bool
|
||||
pulse_output_setup_stream(PulseOutput *po, const pa_sample_spec *ss,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
assert(po != nullptr);
|
||||
assert(po->context != nullptr);
|
||||
|
||||
po->stream = pa_stream_new(po->context, po->name, ss, nullptr);
|
||||
if (po->stream == nullptr) {
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_stream_new() has failed: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
SetError(error, po->context, "pa_stream_new() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -556,11 +548,10 @@ pulse_output_setup_stream(PulseOutput *po, const pa_sample_spec *ss,
|
||||
|
||||
static bool
|
||||
pulse_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
PulseOutput *po = (PulseOutput *)ao;
|
||||
pa_sample_spec ss;
|
||||
int error;
|
||||
|
||||
assert(po->mainloop != nullptr);
|
||||
|
||||
@@ -585,7 +576,7 @@ pulse_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
}
|
||||
}
|
||||
|
||||
if (!pulse_output_wait_connection(po, error_r)) {
|
||||
if (!pulse_output_wait_connection(po, error)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
return false;
|
||||
}
|
||||
@@ -600,22 +591,20 @@ pulse_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
|
||||
/* create a stream .. */
|
||||
|
||||
if (!pulse_output_setup_stream(po, &ss, error_r)) {
|
||||
if (!pulse_output_setup_stream(po, &ss, error)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* .. and connect it (asynchronously) */
|
||||
|
||||
error = pa_stream_connect_playback(po->stream, po->sink,
|
||||
nullptr, pa_stream_flags_t(0),
|
||||
nullptr, nullptr);
|
||||
if (error < 0) {
|
||||
if (pa_stream_connect_playback(po->stream, po->sink,
|
||||
nullptr, pa_stream_flags_t(0),
|
||||
nullptr, nullptr) < 0) {
|
||||
pulse_output_delete_stream(po);
|
||||
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_stream_connect_playback() has failed: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
SetError(error, po->context,
|
||||
"pa_stream_connect_playback() has failed");
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
return false;
|
||||
}
|
||||
@@ -661,7 +650,7 @@ pulse_output_close(struct audio_output *ao)
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
static bool
|
||||
pulse_output_wait_stream(PulseOutput *po, GError **error_r)
|
||||
pulse_output_wait_stream(PulseOutput *po, Error &error)
|
||||
{
|
||||
while (true) {
|
||||
switch (pa_stream_get_state(po->stream)) {
|
||||
@@ -671,10 +660,8 @@ pulse_output_wait_stream(PulseOutput *po, GError **error_r)
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
case PA_STREAM_UNCONNECTED:
|
||||
g_set_error(error_r, pulse_output_quark(),
|
||||
pa_context_errno(po->context),
|
||||
"failed to connect the stream: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
SetError(error, po->context,
|
||||
"failed to connect the stream");
|
||||
return false;
|
||||
|
||||
case PA_STREAM_CREATING:
|
||||
@@ -689,7 +676,7 @@ pulse_output_wait_stream(PulseOutput *po, GError **error_r)
|
||||
*/
|
||||
static bool
|
||||
pulse_output_stream_pause(PulseOutput *po, bool pause,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
pa_operation *o;
|
||||
|
||||
@@ -700,16 +687,12 @@ pulse_output_stream_pause(PulseOutput *po, bool pause,
|
||||
o = pa_stream_cork(po->stream, pause,
|
||||
pulse_output_stream_success_cb, po);
|
||||
if (o == nullptr) {
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_stream_cork() has failed: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
SetError(error, po->context, "pa_stream_cork() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pulse_wait_for_operation(po->mainloop, o)) {
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_stream_cork() has failed: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
SetError(error, po->context, "pa_stream_cork() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -736,10 +719,9 @@ pulse_output_delay(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
PulseOutput *po = (PulseOutput *)ao;
|
||||
int error;
|
||||
|
||||
assert(po->mainloop != nullptr);
|
||||
assert(po->stream != nullptr);
|
||||
@@ -748,7 +730,7 @@ pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
|
||||
/* check if the stream is (already) connected */
|
||||
|
||||
if (!pulse_output_wait_stream(po, error_r)) {
|
||||
if (!pulse_output_wait_stream(po, error)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
return 0;
|
||||
}
|
||||
@@ -758,7 +740,7 @@ pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
/* unpause if previously paused */
|
||||
|
||||
if (pa_stream_is_corked(po->stream) &&
|
||||
!pulse_output_stream_pause(po, false, error_r)) {
|
||||
!pulse_output_stream_pause(po, false, error)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
return 0;
|
||||
}
|
||||
@@ -768,8 +750,7 @@ pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
while (po->writable == 0) {
|
||||
if (pa_stream_is_suspended(po->stream)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"suspended");
|
||||
error.Set(pulse_output_domain, "suspended");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -777,8 +758,7 @@ pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
|
||||
if (pa_stream_get_state(po->stream) != PA_STREAM_READY) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"disconnected");
|
||||
error.Set(pulse_output_domain, "disconnected");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -791,12 +771,11 @@ pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
|
||||
po->writable -= size;
|
||||
|
||||
error = pa_stream_write(po->stream, chunk, size, nullptr,
|
||||
0, PA_SEEK_RELATIVE);
|
||||
int result = pa_stream_write(po->stream, chunk, size, nullptr,
|
||||
0, PA_SEEK_RELATIVE);
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
if (error < 0) {
|
||||
g_set_error(error_r, pulse_output_quark(), error,
|
||||
"%s", pa_strerror(error));
|
||||
if (result < 0) {
|
||||
SetError(error, po->context, "pa_stream_write() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -839,7 +818,6 @@ static bool
|
||||
pulse_output_pause(struct audio_output *ao)
|
||||
{
|
||||
PulseOutput *po = (PulseOutput *)ao;
|
||||
GError *error = nullptr;
|
||||
|
||||
assert(po->mainloop != nullptr);
|
||||
assert(po->stream != nullptr);
|
||||
@@ -848,10 +826,10 @@ pulse_output_pause(struct audio_output *ao)
|
||||
|
||||
/* check if the stream is (already/still) connected */
|
||||
|
||||
if (!pulse_output_wait_stream(po, &error)) {
|
||||
Error error;
|
||||
if (!pulse_output_wait_stream(po, error)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
g_warning("%s", error->message);
|
||||
g_error_free(error);
|
||||
g_warning("%s", error.GetMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -860,10 +838,9 @@ pulse_output_pause(struct audio_output *ao)
|
||||
/* cork the stream */
|
||||
|
||||
if (!pa_stream_is_corked(po->stream) &&
|
||||
!pulse_output_stream_pause(po, true, &error)) {
|
||||
!pulse_output_stream_pause(po, true, error)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
g_warning("%s", error->message);
|
||||
g_error_free(error);
|
||||
g_warning("%s", error.GetMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -878,11 +855,12 @@ pulse_output_test_default_device(void)
|
||||
bool success;
|
||||
|
||||
const config_param empty;
|
||||
PulseOutput *po = (PulseOutput *)pulse_output_init(empty, nullptr);
|
||||
PulseOutput *po = (PulseOutput *)
|
||||
pulse_output_init(empty, IgnoreError());
|
||||
if (po == nullptr)
|
||||
return false;
|
||||
|
||||
success = pulse_output_wait_connection(po, nullptr);
|
||||
success = pulse_output_wait_connection(po, IgnoreError());
|
||||
pulse_output_finish(&po->base);
|
||||
|
||||
return success;
|
||||
|
@@ -20,11 +20,10 @@
|
||||
#ifndef MPD_PULSE_OUTPUT_PLUGIN_HXX
|
||||
#define MPD_PULSE_OUTPUT_PLUGIN_HXX
|
||||
|
||||
#include "gerror.h"
|
||||
|
||||
struct PulseOutput;
|
||||
struct PulseMixer;
|
||||
struct pa_cvolume;
|
||||
class Error;
|
||||
|
||||
extern const struct audio_output_plugin pulse_output_plugin;
|
||||
|
||||
@@ -42,6 +41,6 @@ pulse_output_clear_mixer(PulseOutput *po, PulseMixer *pm);
|
||||
|
||||
bool
|
||||
pulse_output_set_volume(PulseOutput *po,
|
||||
const struct pa_cvolume *volume, GError **error_r);
|
||||
const struct pa_cvolume *volume, Error &error);
|
||||
|
||||
#endif
|
||||
|
@@ -22,6 +22,9 @@
|
||||
#include "OutputAPI.hxx"
|
||||
#include "EncoderPlugin.hxx"
|
||||
#include "EncoderList.hxx"
|
||||
#include "ConfigError.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "system/fd_util.h"
|
||||
#include "open.h"
|
||||
|
||||
@@ -57,7 +60,7 @@ struct RecorderOutput {
|
||||
*/
|
||||
char buffer[32768];
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||
return ao_base_init(&base, &recorder_output_plugin, param,
|
||||
error_r);
|
||||
}
|
||||
@@ -66,27 +69,20 @@ struct RecorderOutput {
|
||||
ao_base_finish(&base);
|
||||
}
|
||||
|
||||
bool Configure(const config_param ¶m, GError **error_r);
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
|
||||
bool WriteToFile(const void *data, size_t length, GError **error_r);
|
||||
bool WriteToFile(const void *data, size_t length, Error &error);
|
||||
|
||||
/**
|
||||
* Writes pending data from the encoder to the output file.
|
||||
*/
|
||||
bool EncoderToFile(GError **error_r);
|
||||
bool EncoderToFile(Error &error);
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
recorder_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("recorder_output");
|
||||
}
|
||||
static constexpr Domain recorder_output_domain("recorder_output");
|
||||
|
||||
inline bool
|
||||
RecorderOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
RecorderOutput::Configure(const config_param ¶m, Error &error)
|
||||
{
|
||||
/* read configuration */
|
||||
|
||||
@@ -94,21 +90,20 @@ RecorderOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
param.GetBlockValue("encoder", "vorbis");
|
||||
const auto encoder_plugin = encoder_plugin_get(encoder_name);
|
||||
if (encoder_plugin == nullptr) {
|
||||
g_set_error(error_r, recorder_output_quark(), 0,
|
||||
"No such encoder: %s", encoder_name);
|
||||
error.Format(config_domain,
|
||||
"No such encoder: %s", encoder_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
path = param.GetBlockValue("path");
|
||||
if (path == nullptr) {
|
||||
g_set_error(error_r, recorder_output_quark(), 0,
|
||||
"'path' not configured");
|
||||
error.Set(config_domain, "'path' not configured");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* initialize encoder */
|
||||
|
||||
encoder = encoder_init(*encoder_plugin, param, error_r);
|
||||
encoder = encoder_init(*encoder_plugin, param, error);
|
||||
if (encoder == nullptr)
|
||||
return false;
|
||||
|
||||
@@ -116,16 +111,16 @@ RecorderOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
}
|
||||
|
||||
static audio_output *
|
||||
recorder_output_init(const config_param ¶m, GError **error_r)
|
||||
recorder_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
RecorderOutput *recorder = new RecorderOutput();
|
||||
|
||||
if (!recorder->Initialize(param, error_r)) {
|
||||
if (!recorder->Initialize(param, error)) {
|
||||
delete recorder;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!recorder->Configure(param, error_r)) {
|
||||
if (!recorder->Configure(param, error)) {
|
||||
recorder->Deinitialize();
|
||||
delete recorder;
|
||||
return nullptr;
|
||||
@@ -145,7 +140,7 @@ recorder_output_finish(struct audio_output *ao)
|
||||
}
|
||||
|
||||
inline bool
|
||||
RecorderOutput::WriteToFile(const void *_data, size_t length, GError **error_r)
|
||||
RecorderOutput::WriteToFile(const void *_data, size_t length, Error &error)
|
||||
{
|
||||
assert(length > 0);
|
||||
|
||||
@@ -159,20 +154,18 @@ RecorderOutput::WriteToFile(const void *_data, size_t length, GError **error_r)
|
||||
return true;
|
||||
} else if (nbytes == 0) {
|
||||
/* shouldn't happen for files */
|
||||
g_set_error(error_r, recorder_output_quark(), 0,
|
||||
"write() returned 0");
|
||||
error.Set(recorder_output_domain,
|
||||
"write() returned 0");
|
||||
return false;
|
||||
} else if (errno != EINTR) {
|
||||
g_set_error(error_r, recorder_output_quark(), 0,
|
||||
"Failed to write to '%s': %s",
|
||||
path, g_strerror(errno));
|
||||
error.FormatErrno("Failed to write to '%s'", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
RecorderOutput::EncoderToFile(GError **error_r)
|
||||
RecorderOutput::EncoderToFile(Error &error)
|
||||
{
|
||||
assert(fd >= 0);
|
||||
|
||||
@@ -185,7 +178,7 @@ RecorderOutput::EncoderToFile(GError **error_r)
|
||||
|
||||
/* write everything into the file */
|
||||
|
||||
if (!WriteToFile(buffer, size, error_r))
|
||||
if (!WriteToFile(buffer, size, error))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -193,7 +186,7 @@ RecorderOutput::EncoderToFile(GError **error_r)
|
||||
static bool
|
||||
recorder_output_open(struct audio_output *ao,
|
||||
AudioFormat &audio_format,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
RecorderOutput *recorder = (RecorderOutput *)ao;
|
||||
|
||||
@@ -203,21 +196,19 @@ recorder_output_open(struct audio_output *ao,
|
||||
O_CREAT|O_WRONLY|O_TRUNC|O_BINARY,
|
||||
0666);
|
||||
if (recorder->fd < 0) {
|
||||
g_set_error(error_r, recorder_output_quark(), 0,
|
||||
"Failed to create '%s': %s",
|
||||
recorder->path, g_strerror(errno));
|
||||
error.FormatErrno("Failed to create '%s'", recorder->path);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* open the encoder */
|
||||
|
||||
if (!encoder_open(recorder->encoder, audio_format, error_r)) {
|
||||
if (!encoder_open(recorder->encoder, audio_format, error)) {
|
||||
close(recorder->fd);
|
||||
unlink(recorder->path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!recorder->EncoderToFile(error_r)) {
|
||||
if (!recorder->EncoderToFile(error)) {
|
||||
encoder_close(recorder->encoder);
|
||||
close(recorder->fd);
|
||||
unlink(recorder->path);
|
||||
@@ -234,8 +225,8 @@ recorder_output_close(struct audio_output *ao)
|
||||
|
||||
/* flush the encoder and write the rest to the file */
|
||||
|
||||
if (encoder_end(recorder->encoder, nullptr))
|
||||
recorder->EncoderToFile(nullptr);
|
||||
if (encoder_end(recorder->encoder, IgnoreError()))
|
||||
recorder->EncoderToFile(IgnoreError());
|
||||
|
||||
/* now really close everything */
|
||||
|
||||
@@ -246,12 +237,12 @@ recorder_output_close(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
recorder_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
RecorderOutput *recorder = (RecorderOutput *)ao;
|
||||
|
||||
return encoder_write(recorder->encoder, chunk, size, error_r) &&
|
||||
recorder->EncoderToFile(error_r)
|
||||
return encoder_write(recorder->encoder, chunk, size, error) &&
|
||||
recorder->EncoderToFile(error)
|
||||
? size : 0;
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,8 @@
|
||||
#include "OutputAPI.hxx"
|
||||
#include "MixerList.hxx"
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@@ -58,11 +60,7 @@ struct RoarOutput {
|
||||
}
|
||||
};
|
||||
|
||||
static inline GQuark
|
||||
roar_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("roar_output");
|
||||
}
|
||||
static constexpr Domain roar_output_domain("roar_output");
|
||||
|
||||
static int
|
||||
roar_output_get_volume_locked(RoarOutput *roar)
|
||||
@@ -120,11 +118,11 @@ roar_configure(RoarOutput *self, const config_param ¶m)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
roar_init(const config_param ¶m, GError **error_r)
|
||||
roar_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
RoarOutput *self = new RoarOutput();
|
||||
|
||||
if (!ao_base_init(&self->base, &roar_output_plugin, param, error_r)) {
|
||||
if (!ao_base_init(&self->base, &roar_output_plugin, param, error)) {
|
||||
delete self;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -178,15 +176,15 @@ roar_use_audio_format(struct roar_audio_info *info,
|
||||
}
|
||||
|
||||
static bool
|
||||
roar_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
|
||||
roar_open(struct audio_output *ao, AudioFormat &audio_format, Error &error)
|
||||
{
|
||||
RoarOutput *self = (RoarOutput *)ao;
|
||||
const ScopeLock protect(self->mutex);
|
||||
|
||||
if (roar_simple_connect(&(self->con), self->host, self->name) < 0)
|
||||
{
|
||||
g_set_error(error, roar_output_quark(), 0,
|
||||
"Failed to connect to Roar server");
|
||||
error.Set(roar_output_domain,
|
||||
"Failed to connect to Roar server");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -194,8 +192,7 @@ roar_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
|
||||
|
||||
if (self->vss == nullptr || self->err != ROAR_ERROR_NONE)
|
||||
{
|
||||
g_set_error(error, roar_output_quark(), 0,
|
||||
"Failed to connect to server");
|
||||
error.Set(roar_output_domain, "Failed to connect to server");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -204,7 +201,7 @@ roar_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
|
||||
if (roar_vs_stream(self->vss, &(self->info), ROAR_DIR_PLAY,
|
||||
&(self->err)) < 0)
|
||||
{
|
||||
g_set_error(error, roar_output_quark(), 0, "Failed to start stream");
|
||||
error.Set(roar_output_domain, "Failed to start stream");
|
||||
return false;
|
||||
}
|
||||
roar_vs_role(self->vss, self->role, &(self->err));
|
||||
@@ -264,21 +261,22 @@ roar_cancel(struct audio_output *ao)
|
||||
}
|
||||
|
||||
static size_t
|
||||
roar_play(struct audio_output *ao, const void *chunk, size_t size, GError **error)
|
||||
roar_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
Error &error)
|
||||
{
|
||||
RoarOutput *self = (RoarOutput *)ao;
|
||||
ssize_t rc;
|
||||
|
||||
if (self->vss == nullptr)
|
||||
{
|
||||
g_set_error(error, roar_output_quark(), 0, "Connection is invalid");
|
||||
error.Set(roar_output_domain, "Connection is invalid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = roar_vs_write(self->vss, chunk, size, &(self->err));
|
||||
if ( rc <= 0 )
|
||||
{
|
||||
g_set_error(error, roar_output_quark(), 0, "Failed to play data");
|
||||
error.Set(roar_output_domain, "Failed to play data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,9 @@
|
||||
#include "OutputAPI.hxx"
|
||||
#include "EncoderPlugin.hxx"
|
||||
#include "EncoderList.hxx"
|
||||
#include "ConfigError.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "mpd_error.h"
|
||||
|
||||
#include <shout/shout.h>
|
||||
@@ -66,28 +69,21 @@ struct ShoutOutput final {
|
||||
shout_free(shout_conn);
|
||||
}
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error) {
|
||||
return ao_base_init(&base, &shout_output_plugin, param,
|
||||
error_r);
|
||||
error);
|
||||
}
|
||||
|
||||
void Deinitialize() {
|
||||
ao_base_finish(&base);
|
||||
}
|
||||
|
||||
bool Configure(const config_param ¶m, GError **error_r);
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
};
|
||||
|
||||
static int shout_init_count;
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
shout_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("shout_output");
|
||||
}
|
||||
static constexpr Domain shout_output_domain("shout_output");
|
||||
|
||||
static const EncoderPlugin *
|
||||
shout_encoder_plugin_get(const char *name)
|
||||
@@ -113,13 +109,13 @@ require_block_string(const config_param ¶m, const char *name)
|
||||
}
|
||||
|
||||
inline bool
|
||||
ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
ShoutOutput::Configure(const config_param ¶m, Error &error)
|
||||
{
|
||||
|
||||
const AudioFormat audio_format = base.config_audio_format;
|
||||
if (!audio_format.IsFullyDefined()) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"Need full audio format specification");
|
||||
error.Set(config_domain,
|
||||
"Need full audio format specification");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -127,8 +123,7 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
const char *mount = require_block_string(param, "mount");
|
||||
unsigned port = param.GetBlockValue("port", 0u);
|
||||
if (port == 0) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"shout port must be configured");
|
||||
error.Set(config_domain, "shout port must be configured");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -145,24 +140,24 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
quality = strtod(value, &test);
|
||||
|
||||
if (*test != '\0' || quality < -1.0 || quality > 10.0) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"shout quality \"%s\" is not a number in the "
|
||||
"range -1 to 10, line %i",
|
||||
value, param.line);
|
||||
error.Format(config_domain,
|
||||
"shout quality \"%s\" is not a number in the "
|
||||
"range -1 to 10, line %i",
|
||||
value, param.line);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param.GetBlockValue("bitrate") != nullptr) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"quality and bitrate are "
|
||||
"both defined");
|
||||
error.Set(config_domain,
|
||||
"quality and bitrate are "
|
||||
"both defined");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
value = param.GetBlockValue("bitrate");
|
||||
if (value == nullptr) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"neither bitrate nor quality defined");
|
||||
error.Set(config_domain,
|
||||
"neither bitrate nor quality defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -170,8 +165,8 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
bitrate = strtol(value, &test, 10);
|
||||
|
||||
if (*test != '\0' || bitrate <= 0) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"bitrate must be a positive integer");
|
||||
error.Set(config_domain,
|
||||
"bitrate must be a positive integer");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -179,13 +174,13 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
const char *encoding = param.GetBlockValue("encoding", "ogg");
|
||||
const auto encoder_plugin = shout_encoder_plugin_get(encoding);
|
||||
if (encoder_plugin == nullptr) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"couldn't find shout encoder plugin \"%s\"",
|
||||
encoding);
|
||||
error.Format(config_domain,
|
||||
"couldn't find shout encoder plugin \"%s\"",
|
||||
encoding);
|
||||
return false;
|
||||
}
|
||||
|
||||
encoder = encoder_init(*encoder_plugin, param, error_r);
|
||||
encoder = encoder_init(*encoder_plugin, param, error);
|
||||
if (encoder == nullptr)
|
||||
return false;
|
||||
|
||||
@@ -200,9 +195,9 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
if (value != nullptr) {
|
||||
if (0 == strcmp(value, "shoutcast") &&
|
||||
0 != strcmp(encoding, "mp3")) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"you cannot stream \"%s\" to shoutcast, use mp3",
|
||||
encoding);
|
||||
error.Format(config_domain,
|
||||
"you cannot stream \"%s\" to shoutcast, use mp3",
|
||||
encoding);
|
||||
return false;
|
||||
} else if (0 == strcmp(value, "shoutcast"))
|
||||
protocol = SHOUT_PROTOCOL_ICY;
|
||||
@@ -211,10 +206,10 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
else if (0 == strcmp(value, "icecast2"))
|
||||
protocol = SHOUT_PROTOCOL_HTTP;
|
||||
else {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"shout protocol \"%s\" is not \"shoutcast\" or "
|
||||
"\"icecast1\"or \"icecast2\"",
|
||||
value);
|
||||
error.Format(config_domain,
|
||||
"shout protocol \"%s\" is not \"shoutcast\" or "
|
||||
"\"icecast1\"or \"icecast2\"",
|
||||
value);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -232,8 +227,7 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
!= SHOUTERR_SUCCESS ||
|
||||
shout_set_protocol(shout_conn, protocol) != SHOUTERR_SUCCESS ||
|
||||
shout_set_agent(shout_conn, "MPD") != SHOUTERR_SUCCESS) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"%s", shout_get_error(shout_conn));
|
||||
error.Set(shout_output_domain, shout_get_error(shout_conn));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -242,22 +236,19 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
|
||||
value = param.GetBlockValue("genre");
|
||||
if (value != nullptr && shout_set_genre(shout_conn, value)) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"%s", shout_get_error(shout_conn));
|
||||
error.Set(shout_output_domain, shout_get_error(shout_conn));
|
||||
return false;
|
||||
}
|
||||
|
||||
value = param.GetBlockValue("description");
|
||||
if (value != nullptr && shout_set_description(shout_conn, value)) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"%s", shout_get_error(shout_conn));
|
||||
error.Set(shout_output_domain, shout_get_error(shout_conn));
|
||||
return false;
|
||||
}
|
||||
|
||||
value = param.GetBlockValue("url");
|
||||
if (value != nullptr && shout_set_url(shout_conn, value)) {
|
||||
g_set_error(error_r, shout_output_quark(), 0,
|
||||
"%s", shout_get_error(shout_conn));
|
||||
error.Set(shout_output_domain, shout_get_error(shout_conn));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -287,15 +278,15 @@ ShoutOutput::Configure(const config_param ¶m, GError **error_r)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
my_shout_init_driver(const config_param ¶m, GError **error_r)
|
||||
my_shout_init_driver(const config_param ¶m, Error &error)
|
||||
{
|
||||
ShoutOutput *sd = new ShoutOutput();
|
||||
if (!sd->Initialize(param, error_r)) {
|
||||
if (!sd->Initialize(param, error)) {
|
||||
delete sd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!sd->Configure(param, error_r)) {
|
||||
if (!sd->Configure(param, error)) {
|
||||
sd->Deinitialize();
|
||||
delete sd;
|
||||
return nullptr;
|
||||
@@ -310,7 +301,7 @@ my_shout_init_driver(const config_param ¶m, GError **error_r)
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_shout_error(ShoutOutput *sd, int err, GError **error)
|
||||
handle_shout_error(ShoutOutput *sd, int err, Error &error)
|
||||
{
|
||||
switch (err) {
|
||||
case SHOUTERR_SUCCESS:
|
||||
@@ -318,19 +309,19 @@ handle_shout_error(ShoutOutput *sd, int err, GError **error)
|
||||
|
||||
case SHOUTERR_UNCONNECTED:
|
||||
case SHOUTERR_SOCKET:
|
||||
g_set_error(error, shout_output_quark(), err,
|
||||
"Lost shout connection to %s:%i: %s",
|
||||
shout_get_host(sd->shout_conn),
|
||||
shout_get_port(sd->shout_conn),
|
||||
shout_get_error(sd->shout_conn));
|
||||
error.Format(shout_output_domain, err,
|
||||
"Lost shout connection to %s:%i: %s",
|
||||
shout_get_host(sd->shout_conn),
|
||||
shout_get_port(sd->shout_conn),
|
||||
shout_get_error(sd->shout_conn));
|
||||
return false;
|
||||
|
||||
default:
|
||||
g_set_error(error, shout_output_quark(), err,
|
||||
"connection to %s:%i error: %s",
|
||||
shout_get_host(sd->shout_conn),
|
||||
shout_get_port(sd->shout_conn),
|
||||
shout_get_error(sd->shout_conn));
|
||||
error.Format(shout_output_domain, err,
|
||||
"connection to %s:%i error: %s",
|
||||
shout_get_host(sd->shout_conn),
|
||||
shout_get_port(sd->shout_conn),
|
||||
shout_get_error(sd->shout_conn));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -338,7 +329,7 @@ handle_shout_error(ShoutOutput *sd, int err, GError **error)
|
||||
}
|
||||
|
||||
static bool
|
||||
write_page(ShoutOutput *sd, GError **error)
|
||||
write_page(ShoutOutput *sd, Error &error)
|
||||
{
|
||||
assert(sd->encoder != nullptr);
|
||||
|
||||
@@ -359,8 +350,8 @@ write_page(ShoutOutput *sd, GError **error)
|
||||
static void close_shout_conn(ShoutOutput * sd)
|
||||
{
|
||||
if (sd->encoder != nullptr) {
|
||||
if (encoder_end(sd->encoder, nullptr))
|
||||
write_page(sd, nullptr);
|
||||
if (encoder_end(sd->encoder, IgnoreError()))
|
||||
write_page(sd, IgnoreError());
|
||||
|
||||
encoder_close(sd->encoder);
|
||||
}
|
||||
@@ -406,7 +397,7 @@ my_shout_close_device(struct audio_output *ao)
|
||||
}
|
||||
|
||||
static bool
|
||||
shout_connect(ShoutOutput *sd, GError **error)
|
||||
shout_connect(ShoutOutput *sd, Error &error)
|
||||
{
|
||||
switch (shout_open(sd->shout_conn)) {
|
||||
case SHOUTERR_SUCCESS:
|
||||
@@ -414,18 +405,18 @@ shout_connect(ShoutOutput *sd, GError **error)
|
||||
return true;
|
||||
|
||||
default:
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"problem opening connection to shout server %s:%i: %s",
|
||||
shout_get_host(sd->shout_conn),
|
||||
shout_get_port(sd->shout_conn),
|
||||
shout_get_error(sd->shout_conn));
|
||||
error.Format(shout_output_domain,
|
||||
"problem opening connection to shout server %s:%i: %s",
|
||||
shout_get_host(sd->shout_conn),
|
||||
shout_get_port(sd->shout_conn),
|
||||
shout_get_error(sd->shout_conn));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
my_shout_open_device(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
ShoutOutput *sd = (ShoutOutput *)ao;
|
||||
|
||||
@@ -460,7 +451,7 @@ my_shout_delay(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
my_shout_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
ShoutOutput *sd = (ShoutOutput *)ao;
|
||||
|
||||
@@ -475,7 +466,7 @@ my_shout_pause(struct audio_output *ao)
|
||||
{
|
||||
static char silence[1020];
|
||||
|
||||
return my_shout_play(ao, silence, sizeof(silence), nullptr);
|
||||
return my_shout_play(ao, silence, sizeof(silence), IgnoreError());
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -508,24 +499,17 @@ static void my_shout_set_tag(struct audio_output *ao,
|
||||
const Tag *tag)
|
||||
{
|
||||
ShoutOutput *sd = (ShoutOutput *)ao;
|
||||
GError *error = nullptr;
|
||||
|
||||
if (sd->encoder->plugin.tag != nullptr) {
|
||||
/* encoder plugin supports stream tags */
|
||||
|
||||
if (!encoder_pre_tag(sd->encoder, &error)) {
|
||||
g_warning("%s", error->message);
|
||||
g_error_free(error);
|
||||
Error error;
|
||||
if (!encoder_pre_tag(sd->encoder, error) ||
|
||||
!write_page(sd, error) ||
|
||||
!encoder_tag(sd->encoder, tag, error)) {
|
||||
g_warning("%s", error.GetMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!write_page(sd, nullptr))
|
||||
return;
|
||||
|
||||
if (!encoder_tag(sd->encoder, tag, &error)) {
|
||||
g_warning("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
} else {
|
||||
/* no stream tag support: fall back to icy-metadata */
|
||||
char song[1024];
|
||||
@@ -538,7 +522,7 @@ static void my_shout_set_tag(struct audio_output *ao,
|
||||
}
|
||||
}
|
||||
|
||||
write_page(sd, nullptr);
|
||||
write_page(sd, IgnoreError());
|
||||
}
|
||||
|
||||
const struct audio_output_plugin shout_output_plugin = {
|
||||
|
@@ -21,8 +21,7 @@
|
||||
#include "SolarisOutputPlugin.hxx"
|
||||
#include "OutputAPI.hxx"
|
||||
#include "system/fd_util.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <sys/stropts.h>
|
||||
#include <sys/types.h>
|
||||
@@ -61,7 +60,7 @@ struct SolarisOutput {
|
||||
|
||||
int fd;
|
||||
|
||||
bool Initialize(const config_param ¶m, GError **error_r) {
|
||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||
return ao_base_init(&base, &solaris_output_plugin, param,
|
||||
error_r);
|
||||
}
|
||||
@@ -71,15 +70,6 @@ struct SolarisOutput {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
solaris_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("solaris_output");
|
||||
}
|
||||
|
||||
static bool
|
||||
solaris_output_test_default_device(void)
|
||||
{
|
||||
@@ -90,7 +80,7 @@ solaris_output_test_default_device(void)
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
solaris_output_init(const config_param ¶m, GError **error_r)
|
||||
solaris_output_init(const config_param ¶m, Error &error_r)
|
||||
{
|
||||
SolarisOutput *so = new SolarisOutput();
|
||||
if (!so->Initialize(param, error_r)) {
|
||||
@@ -114,7 +104,7 @@ solaris_output_finish(struct audio_output *ao)
|
||||
|
||||
static bool
|
||||
solaris_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
SolarisOutput *so = (SolarisOutput *)ao;
|
||||
struct audio_info info;
|
||||
@@ -128,9 +118,8 @@ solaris_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
|
||||
so->fd = open_cloexec(so->device, O_WRONLY|O_NONBLOCK, 0);
|
||||
if (so->fd < 0) {
|
||||
g_set_error(error, solaris_output_quark(), errno,
|
||||
"Failed to open %s: %s",
|
||||
so->device, g_strerror(errno));
|
||||
error.FormatErrno("Failed to open %s",
|
||||
so->device);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -144,8 +133,7 @@ solaris_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
|
||||
ret = ioctl(so->fd, AUDIO_GETINFO, &info);
|
||||
if (ret < 0) {
|
||||
g_set_error(error, solaris_output_quark(), errno,
|
||||
"AUDIO_GETINFO failed: %s", g_strerror(errno));
|
||||
error.SetErrno("AUDIO_GETINFO failed");
|
||||
close(so->fd);
|
||||
return false;
|
||||
}
|
||||
@@ -157,8 +145,7 @@ solaris_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
|
||||
ret = ioctl(so->fd, AUDIO_SETINFO, &info);
|
||||
if (ret < 0) {
|
||||
g_set_error(error, solaris_output_quark(), errno,
|
||||
"AUDIO_SETINFO failed: %s", g_strerror(errno));
|
||||
error.SetErrno("AUDIO_SETINFO failed");
|
||||
close(so->fd);
|
||||
return false;
|
||||
}
|
||||
@@ -176,15 +163,14 @@ solaris_output_close(struct audio_output *ao)
|
||||
|
||||
static size_t
|
||||
solaris_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error)
|
||||
Error &error)
|
||||
{
|
||||
SolarisOutput *so = (SolarisOutput *)ao;
|
||||
ssize_t nbytes;
|
||||
|
||||
nbytes = write(so->fd, chunk, size);
|
||||
if (nbytes <= 0) {
|
||||
g_set_error(error, solaris_output_quark(), errno,
|
||||
"Write failed: %s", g_strerror(errno));
|
||||
error.SetErrno("Write failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include "OutputAPI.hxx"
|
||||
#include "pcm/PcmBuffer.hxx"
|
||||
#include "MixerList.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -51,14 +53,7 @@ struct WinmmOutput {
|
||||
unsigned next_buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
winmm_output_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("winmm_output");
|
||||
}
|
||||
static constexpr Domain winmm_output_domain("winmm_output");
|
||||
|
||||
HWAVEOUT
|
||||
winmm_output_get_handle(WinmmOutput *output)
|
||||
@@ -73,7 +68,7 @@ winmm_output_test_default_device(void)
|
||||
}
|
||||
|
||||
static bool
|
||||
get_device_id(const char *device_name, UINT *device_id, GError **error_r)
|
||||
get_device_id(const char *device_name, UINT *device_id, Error &error)
|
||||
{
|
||||
/* if device is not specified use wave mapper */
|
||||
if (device_name == nullptr) {
|
||||
@@ -108,22 +103,22 @@ get_device_id(const char *device_name, UINT *device_id, GError **error_r)
|
||||
}
|
||||
|
||||
fail:
|
||||
g_set_error(error_r, winmm_output_quark(), 0,
|
||||
"device \"%s\" is not found", device_name);
|
||||
error.Format(winmm_output_domain,
|
||||
"device \"%s\" is not found", device_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct audio_output *
|
||||
winmm_output_init(const config_param ¶m, GError **error_r)
|
||||
winmm_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
WinmmOutput *wo = new WinmmOutput();
|
||||
if (!ao_base_init(&wo->base, &winmm_output_plugin, param, error_r)) {
|
||||
if (!ao_base_init(&wo->base, &winmm_output_plugin, param, error)) {
|
||||
g_free(wo);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *device = param.GetBlockValue("device");
|
||||
if (!get_device_id(device, &wo->device_id, error_r)) {
|
||||
if (!get_device_id(device, &wo->device_id, error)) {
|
||||
ao_base_finish(&wo->base);
|
||||
g_free(wo);
|
||||
return nullptr;
|
||||
@@ -143,14 +138,13 @@ winmm_output_finish(struct audio_output *ao)
|
||||
|
||||
static bool
|
||||
winmm_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
WinmmOutput *wo = (WinmmOutput *)ao;
|
||||
|
||||
wo->event = CreateEvent(nullptr, false, false, nullptr);
|
||||
if (wo->event == nullptr) {
|
||||
g_set_error(error_r, winmm_output_quark(), 0,
|
||||
"CreateEvent() failed");
|
||||
error.Set(winmm_output_domain, "CreateEvent() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -186,8 +180,7 @@ winmm_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||
(DWORD_PTR)wo->event, 0, CALLBACK_EVENT);
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
CloseHandle(wo->event);
|
||||
g_set_error(error_r, winmm_output_quark(), result,
|
||||
"waveOutOpen() failed");
|
||||
error.Set(winmm_output_domain, "waveOutOpen() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -219,7 +212,7 @@ winmm_output_close(struct audio_output *ao)
|
||||
static bool
|
||||
winmm_set_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
|
||||
const void *data, size_t size,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
void *dest = buffer->buffer.Get(size);
|
||||
assert(dest != nullptr);
|
||||
@@ -233,8 +226,8 @@ winmm_set_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
|
||||
MMRESULT result = waveOutPrepareHeader(wo->handle, &buffer->hdr,
|
||||
sizeof(buffer->hdr));
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
g_set_error(error_r, winmm_output_quark(), result,
|
||||
"waveOutPrepareHeader() failed");
|
||||
error.Set(winmm_output_domain, result,
|
||||
"waveOutPrepareHeader() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -246,7 +239,7 @@ winmm_set_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
|
||||
*/
|
||||
static bool
|
||||
winmm_drain_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
|
||||
GError **error_r)
|
||||
Error &error)
|
||||
{
|
||||
if ((buffer->hdr.dwFlags & WHDR_DONE) == WHDR_DONE)
|
||||
/* already finished */
|
||||
@@ -259,8 +252,8 @@ winmm_drain_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
|
||||
if (result == MMSYSERR_NOERROR)
|
||||
return true;
|
||||
else if (result != WAVERR_STILLPLAYING) {
|
||||
g_set_error(error_r, winmm_output_quark(), result,
|
||||
"waveOutUnprepareHeader() failed");
|
||||
error.Set(winmm_output_domain, result,
|
||||
"waveOutUnprepareHeader() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -270,14 +263,14 @@ winmm_drain_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
|
||||
}
|
||||
|
||||
static size_t
|
||||
winmm_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error_r)
|
||||
winmm_output_play(struct audio_output *ao, const void *chunk, size_t size, Error &error)
|
||||
{
|
||||
WinmmOutput *wo = (WinmmOutput *)ao;
|
||||
|
||||
/* get the next buffer from the ring and prepare it */
|
||||
WinmmBuffer *buffer = &wo->buffers[wo->next_buffer];
|
||||
if (!winmm_drain_buffer(wo, buffer, error_r) ||
|
||||
!winmm_set_buffer(wo, buffer, chunk, size, error_r))
|
||||
if (!winmm_drain_buffer(wo, buffer, error) ||
|
||||
!winmm_set_buffer(wo, buffer, chunk, size, error))
|
||||
return 0;
|
||||
|
||||
/* enqueue the buffer */
|
||||
@@ -286,8 +279,8 @@ winmm_output_play(struct audio_output *ao, const void *chunk, size_t size, GErro
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
waveOutUnprepareHeader(wo->handle, &buffer->hdr,
|
||||
sizeof(buffer->hdr));
|
||||
g_set_error(error_r, winmm_output_quark(), result,
|
||||
"waveOutWrite() failed");
|
||||
error.Set(winmm_output_domain, result,
|
||||
"waveOutWrite() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -299,14 +292,14 @@ winmm_output_play(struct audio_output *ao, const void *chunk, size_t size, GErro
|
||||
}
|
||||
|
||||
static bool
|
||||
winmm_drain_all_buffers(WinmmOutput *wo, GError **error_r)
|
||||
winmm_drain_all_buffers(WinmmOutput *wo, Error &error)
|
||||
{
|
||||
for (unsigned i = wo->next_buffer; i < G_N_ELEMENTS(wo->buffers); ++i)
|
||||
if (!winmm_drain_buffer(wo, &wo->buffers[i], error_r))
|
||||
if (!winmm_drain_buffer(wo, &wo->buffers[i], error))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < wo->next_buffer; ++i)
|
||||
if (!winmm_drain_buffer(wo, &wo->buffers[i], error_r))
|
||||
if (!winmm_drain_buffer(wo, &wo->buffers[i], error))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -329,7 +322,7 @@ winmm_output_drain(struct audio_output *ao)
|
||||
{
|
||||
WinmmOutput *wo = (WinmmOutput *)ao;
|
||||
|
||||
if (!winmm_drain_all_buffers(wo, nullptr))
|
||||
if (!winmm_drain_all_buffers(wo, IgnoreError()))
|
||||
winmm_stop(wo);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user