aboutsummaryrefslogtreecommitdiffstats
path: root/src/output
diff options
context:
space:
mode:
Diffstat (limited to 'src/output')
-rw-r--r--src/output/AlsaOutputPlugin.cxx (renamed from src/output/alsa_output_plugin.c)318
-rw-r--r--src/output/AlsaOutputPlugin.hxx (renamed from src/output/alsa_output_plugin.h)6
-rw-r--r--src/output/AoOutputPlugin.cxx (renamed from src/output/ao_output_plugin.c)161
-rw-r--r--src/output/AoOutputPlugin.hxx (renamed from src/output/ao_output_plugin.h)6
-rw-r--r--src/output/FifoOutputPlugin.cxx (renamed from src/output/fifo_output_plugin.c)235
-rw-r--r--src/output/FifoOutputPlugin.hxx (renamed from src/output/fifo_output_plugin.h)6
-rw-r--r--src/output/HttpdClient.cxx444
-rw-r--r--src/output/HttpdClient.hxx186
-rw-r--r--src/output/HttpdInternal.hxx (renamed from src/output/httpd_internal.h)140
-rw-r--r--src/output/HttpdOutputPlugin.cxx568
-rw-r--r--src/output/HttpdOutputPlugin.hxx (renamed from src/output/httpd_output_plugin.h)6
-rw-r--r--src/output/JackOutputPlugin.cxx (renamed from src/output/jack_output_plugin.c)245
-rw-r--r--src/output/JackOutputPlugin.hxx (renamed from src/output/jack_output_plugin.h)6
-rw-r--r--src/output/NullOutputPlugin.cxx143
-rw-r--r--src/output/NullOutputPlugin.hxx (renamed from src/output/null_output_plugin.h)6
-rw-r--r--src/output/OSXOutputPlugin.cxx (renamed from src/output/osx_output_plugin.c)118
-rw-r--r--src/output/OSXOutputPlugin.hxx (renamed from src/output/osx_output_plugin.h)6
-rw-r--r--src/output/OpenALOutputPlugin.cxx (renamed from src/output/openal_output_plugin.c)108
-rw-r--r--src/output/OpenALOutputPlugin.hxx (renamed from src/output/openal_output_plugin.h)6
-rw-r--r--src/output/OssOutputPlugin.cxx (renamed from src/output/oss_output_plugin.c)237
-rw-r--r--src/output/OssOutputPlugin.hxx (renamed from src/output/oss_output_plugin.h)6
-rw-r--r--src/output/PipeOutputPlugin.cxx (renamed from src/output/pipe_output_plugin.c)89
-rw-r--r--src/output/PipeOutputPlugin.hxx (renamed from src/output/pipe_output_plugin.h)6
-rw-r--r--src/output/PulseOutputPlugin.cxx (renamed from src/output/pulse_output_plugin.c)315
-rw-r--r--src/output/PulseOutputPlugin.hxx (renamed from src/output/pulse_output_plugin.h)32
-rw-r--r--src/output/RecorderOutputPlugin.cxx (renamed from src/output/recorder_output_plugin.c)157
-rw-r--r--src/output/RecorderOutputPlugin.hxx (renamed from src/output/recorder_output_plugin.h)6
-rw-r--r--src/output/RoarOutputPlugin.cxx (renamed from src/output/roar_output_plugin.c)190
-rw-r--r--src/output/RoarOutputPlugin.hxx (renamed from src/output/roar_output_plugin.h)10
-rw-r--r--src/output/ShoutOutputPlugin.cxx (renamed from src/output/shout_output_plugin.c)379
-rw-r--r--src/output/ShoutOutputPlugin.hxx (renamed from src/output/shout_output_plugin.h)6
-rw-r--r--src/output/SolarisOutputPlugin.cxx (renamed from src/output/solaris_output_plugin.c)75
-rw-r--r--src/output/SolarisOutputPlugin.hxx (renamed from src/output/solaris_output_plugin.h)6
-rw-r--r--src/output/WinmmOutputPlugin.cxx (renamed from src/output/winmm_output_plugin.c)130
-rw-r--r--src/output/WinmmOutputPlugin.hxx (renamed from src/output/winmm_output_plugin.h)15
-rw-r--r--src/output/ffado_output_plugin.c359
-rw-r--r--src/output/ffado_output_plugin.h25
-rw-r--r--src/output/httpd_client.c764
-rw-r--r--src/output/httpd_client.h71
-rw-r--r--src/output/httpd_output_plugin.c623
-rw-r--r--src/output/mvp_output_plugin.c344
-rw-r--r--src/output/mvp_output_plugin.h25
-rw-r--r--src/output/null_output_plugin.c129
43 files changed, 2985 insertions, 3728 deletions
diff --git a/src/output/alsa_output_plugin.c b/src/output/AlsaOutputPlugin.cxx
index d8b184273..b26a3e1df 100644
--- a/src/output/alsa_output_plugin.c
+++ b/src/output/AlsaOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,14 +18,17 @@
*/
#include "config.h"
-#include "alsa_output_plugin.h"
-#include "output_api.h"
-#include "mixer_list.h"
-#include "pcm_export.h"
+#include "AlsaOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "MixerList.hxx"
+#include "pcm/PcmExport.hxx"
+#include "util/Manual.hxx"
#include <glib.h>
#include <alsa/asoundlib.h>
+#include <string>
+
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "alsa"
@@ -34,23 +37,23 @@
static const char default_device[] = "default";
-enum {
- MPD_ALSA_BUFFER_TIME_US = 500000,
-};
+static constexpr unsigned MPD_ALSA_BUFFER_TIME_US = 500000;
#define MPD_ALSA_RETRY_NR 5
typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t * pcm, const void *buffer,
snd_pcm_uframes_t size);
-struct alsa_data {
+struct AlsaOutput {
struct audio_output base;
- struct pcm_export_state export;
+ Manual<PcmExport> pcm_export;
- /** the configured name of the ALSA device; NULL for the
- default device */
- char *device;
+ /**
+ * The configured name of the ALSA device; empty for the
+ * default device
+ */
+ std::string device;
/** use memory mapped I/O? */
bool use_mmap;
@@ -101,6 +104,25 @@ struct alsa_data {
* The number of frames written in the current period.
*/
snd_pcm_uframes_t period_position;
+
+ /**
+ * This buffer gets allocated after opening the ALSA device.
+ * It contains silence samples, enough to fill one period (see
+ * #period_frames).
+ */
+ void *silence;
+
+ AlsaOutput():mode(0), writei(snd_pcm_writei) {
+ }
+
+ bool Init(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &alsa_output_plugin,
+ param, error_r);
+ }
+
+ void Deinit() {
+ ao_base_finish(&base);
+ }
};
/**
@@ -113,58 +135,47 @@ alsa_output_quark(void)
}
static const char *
-alsa_device(const struct alsa_data *ad)
+alsa_device(const AlsaOutput *ad)
{
- return ad->device != NULL ? ad->device : default_device;
-}
-
-static struct alsa_data *
-alsa_data_new(void)
-{
- struct alsa_data *ret = g_new(struct alsa_data, 1);
-
- ret->mode = 0;
- ret->writei = snd_pcm_writei;
-
- return ret;
+ return ad->device.empty() ? default_device : ad->device.c_str();
}
static void
-alsa_configure(struct alsa_data *ad, const struct config_param *param)
+alsa_configure(AlsaOutput *ad, const config_param &param)
{
- ad->device = config_dup_block_string(param, "device", NULL);
+ ad->device = param.GetBlockValue("device", "");
- ad->use_mmap = config_get_block_bool(param, "use_mmap", false);
+ ad->use_mmap = param.GetBlockValue("use_mmap", false);
- ad->dsd_usb = config_get_block_bool(param, "dsd_usb", false);
+ ad->dsd_usb = param.GetBlockValue("dsd_usb", false);
- ad->buffer_time = config_get_block_unsigned(param, "buffer_time",
- MPD_ALSA_BUFFER_TIME_US);
- ad->period_time = config_get_block_unsigned(param, "period_time", 0);
+ ad->buffer_time = param.GetBlockValue("buffer_time",
+ MPD_ALSA_BUFFER_TIME_US);
+ ad->period_time = param.GetBlockValue("period_time", 0u);
#ifdef SND_PCM_NO_AUTO_RESAMPLE
- if (!config_get_block_bool(param, "auto_resample", true))
+ if (!param.GetBlockValue("auto_resample", true))
ad->mode |= SND_PCM_NO_AUTO_RESAMPLE;
#endif
#ifdef SND_PCM_NO_AUTO_CHANNELS
- if (!config_get_block_bool(param, "auto_channels", true))
+ if (!param.GetBlockValue("auto_channels", true))
ad->mode |= SND_PCM_NO_AUTO_CHANNELS;
#endif
#ifdef SND_PCM_NO_AUTO_FORMAT
- if (!config_get_block_bool(param, "auto_format", true))
+ if (!param.GetBlockValue("auto_format", true))
ad->mode |= SND_PCM_NO_AUTO_FORMAT;
#endif
}
static struct audio_output *
-alsa_init(const struct config_param *param, GError **error_r)
+alsa_init(const config_param &param, GError **error_r)
{
- struct alsa_data *ad = alsa_data_new();
+ AlsaOutput *ad = new AlsaOutput();
- if (!ao_base_init(&ad->base, &alsa_output_plugin, param, error_r)) {
- g_free(ad);
+ if (!ad->Init(param, error_r)) {
+ delete ad;
return NULL;
}
@@ -176,12 +187,10 @@ alsa_init(const struct config_param *param, GError **error_r)
static void
alsa_finish(struct audio_output *ao)
{
- struct alsa_data *ad = (struct alsa_data *)ao;
-
- ao_base_finish(&ad->base);
+ AlsaOutput *ad = (AlsaOutput *)ao;
- g_free(ad->device);
- g_free(ad);
+ ad->Deinit();
+ delete ad;
/* free libasound's config cache */
snd_config_update_free_global();
@@ -190,18 +199,18 @@ alsa_finish(struct audio_output *ao)
static bool
alsa_output_enable(struct audio_output *ao, G_GNUC_UNUSED GError **error_r)
{
- struct alsa_data *ad = (struct alsa_data *)ao;
+ AlsaOutput *ad = (AlsaOutput *)ao;
- pcm_export_init(&ad->export);
+ ad->pcm_export.Construct();
return true;
}
static void
alsa_output_disable(struct audio_output *ao)
{
- struct alsa_data *ad = (struct alsa_data *)ao;
+ AlsaOutput *ad = (AlsaOutput *)ao;
- pcm_export_deinit(&ad->export);
+ ad->pcm_export.Destruct();
}
static bool
@@ -222,31 +231,31 @@ alsa_test_default_device(void)
}
static snd_pcm_format_t
-get_bitformat(enum sample_format sample_format)
+get_bitformat(SampleFormat sample_format)
{
switch (sample_format) {
- case SAMPLE_FORMAT_UNDEFINED:
- case SAMPLE_FORMAT_DSD:
+ case SampleFormat::UNDEFINED:
+ case SampleFormat::DSD:
return SND_PCM_FORMAT_UNKNOWN;
- case SAMPLE_FORMAT_S8:
+ case SampleFormat::S8:
return SND_PCM_FORMAT_S8;
- case SAMPLE_FORMAT_S16:
+ case SampleFormat::S16:
return SND_PCM_FORMAT_S16;
- case SAMPLE_FORMAT_S24_P32:
+ case SampleFormat::S24_P32:
return SND_PCM_FORMAT_S24;
- case SAMPLE_FORMAT_S32:
+ case SampleFormat::S32:
return SND_PCM_FORMAT_S32;
- case SAMPLE_FORMAT_FLOAT:
+ case SampleFormat::FLOAT:
return SND_PCM_FORMAT_FLOAT;
}
assert(false);
- return SND_PCM_FORMAT_UNKNOWN;
+ gcc_unreachable();
}
static snd_pcm_format_t
@@ -313,7 +322,7 @@ alsa_try_format_or_packed(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
*/
static int
alsa_output_try_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
- enum sample_format sample_format,
+ SampleFormat sample_format,
bool *packed_r, bool *reverse_endian_r)
{
snd_pcm_format_t alsa_format = get_bitformat(sample_format);
@@ -344,35 +353,36 @@ alsa_output_try_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
*/
static int
alsa_output_setup_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
- struct audio_format *audio_format,
+ AudioFormat &audio_format,
bool *packed_r, bool *reverse_endian_r)
{
/* try the input format first */
- int err = alsa_output_try_format(pcm, hwparams, audio_format->format,
+ int err = alsa_output_try_format(pcm, hwparams,
+ audio_format.format,
packed_r, reverse_endian_r);
/* if unsupported by the hardware, try other formats */
- static const enum sample_format probe_formats[] = {
- SAMPLE_FORMAT_S24_P32,
- SAMPLE_FORMAT_S32,
- SAMPLE_FORMAT_S16,
- SAMPLE_FORMAT_S8,
- SAMPLE_FORMAT_UNDEFINED,
+ static const SampleFormat probe_formats[] = {
+ SampleFormat::S24_P32,
+ SampleFormat::S32,
+ SampleFormat::S16,
+ SampleFormat::S8,
+ SampleFormat::UNDEFINED,
};
for (unsigned i = 0;
- err == -EINVAL && probe_formats[i] != SAMPLE_FORMAT_UNDEFINED;
+ err == -EINVAL && probe_formats[i] != SampleFormat::UNDEFINED;
++i) {
- const enum sample_format mpd_format = probe_formats[i];
- if (mpd_format == audio_format->format)
+ const SampleFormat mpd_format = probe_formats[i];
+ if (mpd_format == audio_format.format)
continue;
err = alsa_output_try_format(pcm, hwparams, mpd_format,
packed_r, reverse_endian_r);
if (err == 0)
- audio_format->format = mpd_format;
+ audio_format.format = mpd_format;
}
return err;
@@ -383,15 +393,11 @@ alsa_output_setup_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
* the configured settings and the audio format.
*/
static bool
-alsa_setup(struct alsa_data *ad, struct audio_format *audio_format,
+alsa_setup(AlsaOutput *ad, AudioFormat &audio_format,
bool *packed_r, bool *reverse_endian_r, GError **error)
{
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_sw_params_t *swparams;
- unsigned int sample_rate = audio_format->sample_rate;
- unsigned int channels = audio_format->channels;
- snd_pcm_uframes_t alsa_buffer_size;
- snd_pcm_uframes_t alsa_period_size;
+ unsigned int sample_rate = audio_format.sample_rate;
+ unsigned int channels = audio_format.channels;
int err;
const char *cmd = NULL;
int retry = MPD_ALSA_RETRY_NR;
@@ -401,6 +407,7 @@ alsa_setup(struct alsa_data *ad, struct audio_format *audio_format,
period_time_ro = period_time = ad->period_time;
configure_hw:
/* configure HW params */
+ snd_pcm_hw_params_t *hwparams;
snd_pcm_hw_params_alloca(&hwparams);
cmd = "snd_pcm_hw_params_any";
err = snd_pcm_hw_params_any(ad->pcm, hwparams);
@@ -434,7 +441,7 @@ configure_hw:
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),
+ sample_format_to_string(audio_format.format),
snd_strerror(-err));
return false;
}
@@ -449,21 +456,21 @@ configure_hw:
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,
+ alsa_device(ad), (int)audio_format.channels,
snd_strerror(-err));
return false;
}
- audio_format->channels = (int8_t)channels;
+ audio_format.channels = (int8_t)channels;
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);
+ alsa_device(ad), audio_format.sample_rate);
return false;
}
- audio_format->sample_rate = sample_rate;
+ audio_format.sample_rate = sample_rate;
snd_pcm_uframes_t buffer_size_min, buffer_size_max;
snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min);
@@ -525,11 +532,13 @@ configure_hw:
if (retry != MPD_ALSA_RETRY_NR)
g_debug("ALSA period_time set to %d\n", period_time);
+ snd_pcm_uframes_t alsa_buffer_size;
cmd = "snd_pcm_hw_params_get_buffer_size";
err = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size);
if (err < 0)
goto error;
+ snd_pcm_uframes_t alsa_period_size;
cmd = "snd_pcm_hw_params_get_period_size";
err = snd_pcm_hw_params_get_period_size(hwparams, &alsa_period_size,
NULL);
@@ -537,6 +546,7 @@ configure_hw:
goto error;
/* configure SW params */
+ snd_pcm_sw_params_t *swparams;
snd_pcm_sw_params_alloca(&swparams);
cmd = "snd_pcm_sw_params_current";
@@ -576,6 +586,11 @@ configure_hw:
ad->period_frames = alsa_period_size;
ad->period_position = 0;
+ ad->silence = g_malloc(snd_pcm_frames_to_bytes(ad->pcm,
+ alsa_period_size));
+ snd_pcm_format_set_silence(format, ad->silence,
+ alsa_period_size * channels);
+
return true;
error:
@@ -586,22 +601,22 @@ error:
}
static bool
-alsa_setup_dsd(struct alsa_data *ad, struct audio_format *audio_format,
+alsa_setup_dsd(AlsaOutput *ad, const AudioFormat audio_format,
bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
GError **error_r)
{
assert(ad->dsd_usb);
- assert(audio_format->format == SAMPLE_FORMAT_DSD);
+ assert(audio_format.format == SampleFormat::DSD);
/* pass 24 bit to alsa_setup() */
- struct audio_format usb_format = *audio_format;
- usb_format.format = SAMPLE_FORMAT_S24_P32;
+ AudioFormat usb_format = audio_format;
+ usb_format.format = SampleFormat::S24_P32;
usb_format.sample_rate /= 2;
- const struct audio_format check = usb_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_r))
return false;
/* if the device allows only 32 bit, shift all DSD-over-USB
@@ -609,16 +624,17 @@ alsa_setup_dsd(struct alsa_data *ad, struct audio_format *audio_format,
the DSD-over-USB documentation does not specify whether
this is legal, but there is anecdotical evidence that this
is possible (and the only option for some devices) */
- *shift8_r = usb_format.format == SAMPLE_FORMAT_S32;
- if (usb_format.format == SAMPLE_FORMAT_S32)
- usb_format.format = SAMPLE_FORMAT_S24_P32;
+ *shift8_r = usb_format.format == SampleFormat::S32;
+ if (usb_format.format == SampleFormat::S32)
+ usb_format.format = SampleFormat::S24_P32;
- if (!audio_format_equals(&usb_format, &check)) {
+ 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));
+ g_free(ad->silence);
return false;
}
@@ -626,13 +642,13 @@ alsa_setup_dsd(struct alsa_data *ad, struct audio_format *audio_format,
}
static bool
-alsa_setup_or_dsd(struct alsa_data *ad, struct audio_format *audio_format,
+alsa_setup_or_dsd(AlsaOutput *ad, AudioFormat &audio_format,
GError **error_r)
{
bool shift8 = false, packed, reverse_endian;
const bool dsd_usb = ad->dsd_usb &&
- audio_format->format == SAMPLE_FORMAT_DSD;
+ audio_format.format == SampleFormat::DSD;
const bool success = dsd_usb
? alsa_setup_dsd(ad, audio_format,
&shift8, &packed, &reverse_endian,
@@ -642,21 +658,19 @@ alsa_setup_or_dsd(struct alsa_data *ad, struct audio_format *audio_format,
if (!success)
return false;
- pcm_export_open(&ad->export,
- audio_format->format, audio_format->channels,
- dsd_usb, shift8, packed, reverse_endian);
+ ad->pcm_export->Open(audio_format.format,
+ audio_format.channels,
+ dsd_usb, shift8, packed, reverse_endian);
return true;
}
static bool
-alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **error)
+alsa_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
{
- struct alsa_data *ad = (struct alsa_data *)ao;
- int err;
- bool success;
+ AlsaOutput *ad = (AlsaOutput *)ao;
- err = snd_pcm_open(&ad->pcm, alsa_device(ad),
- SND_PCM_STREAM_PLAYBACK, ad->mode);
+ 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,
"Failed to open ALSA device \"%s\": %s",
@@ -667,20 +681,28 @@ alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **e
g_debug("opened %s type=%s", snd_pcm_name(ad->pcm),
snd_pcm_type_name(snd_pcm_type(ad->pcm)));
- success = alsa_setup_or_dsd(ad, audio_format, error);
- if (!success) {
+ if (!alsa_setup_or_dsd(ad, audio_format, error)) {
snd_pcm_close(ad->pcm);
return false;
}
- ad->in_frame_size = audio_format_frame_size(audio_format);
- ad->out_frame_size = pcm_export_frame_size(&ad->export, audio_format);
+ ad->in_frame_size = audio_format.GetFrameSize();
+ ad->out_frame_size = ad->pcm_export->GetFrameSize(audio_format);
return true;
}
+/**
+ * Write silence to the ALSA device.
+ */
+static void
+alsa_write_silence(AlsaOutput *ad, snd_pcm_uframes_t nframes)
+{
+ ad->writei(ad->pcm, ad->silence, nframes);
+}
+
static int
-alsa_recover(struct alsa_data *ad, int err)
+alsa_recover(AlsaOutput *ad, int err)
{
if (err == -EPIPE) {
g_debug("Underrun on ALSA device \"%s\"\n", alsa_device(ad));
@@ -701,6 +723,26 @@ alsa_recover(struct alsa_data *ad, int err)
case SND_PCM_STATE_XRUN:
ad->period_position = 0;
err = snd_pcm_prepare(ad->pcm);
+
+ if (err == 0) {
+ /* this works around a driver bug observed on
+ the Raspberry Pi: after snd_pcm_drop(), the
+ whole ring buffer must be invalidated, but
+ the snd_pcm_prepare() call above makes the
+ driver play random data that just happens
+ to be still in the buffer; by adding and
+ cancelling some silence, this bug does not
+ occur */
+ alsa_write_silence(ad, ad->period_frames);
+
+ /* cancel the silence data right away to avoid
+ increasing latency; even though this
+ function call invalidates the portion of
+ silence, the driver seems to avoid the
+ bug */
+ snd_pcm_reset(ad->pcm);
+ }
+
break;
case SND_PCM_STATE_DISCONNECTED:
break;
@@ -719,7 +761,7 @@ alsa_recover(struct alsa_data *ad, int err)
static void
alsa_drain(struct audio_output *ao)
{
- struct alsa_data *ad = (struct alsa_data *)ao;
+ AlsaOutput *ad = (AlsaOutput *)ao;
if (snd_pcm_state(ad->pcm) != SND_PCM_STATE_RUNNING)
return;
@@ -729,20 +771,7 @@ alsa_drain(struct audio_output *ao)
period */
snd_pcm_uframes_t nframes =
ad->period_frames - ad->period_position;
- size_t nbytes = nframes * ad->out_frame_size;
- void *buffer = g_malloc(nbytes);
- snd_pcm_hw_params_t *params;
- snd_pcm_format_t format;
- unsigned channels;
-
- snd_pcm_hw_params_alloca(&params);
- snd_pcm_hw_params_current(ad->pcm, params);
- snd_pcm_hw_params_get_format(params, &format);
- snd_pcm_hw_params_get_channels(params, &channels);
-
- snd_pcm_format_set_silence(format, buffer, nframes * channels);
- ad->writei(ad->pcm, buffer, nframes);
- g_free(buffer);
+ alsa_write_silence(ad, nframes);
}
snd_pcm_drain(ad->pcm);
@@ -753,7 +782,7 @@ alsa_drain(struct audio_output *ao)
static void
alsa_cancel(struct audio_output *ao)
{
- struct alsa_data *ad = (struct alsa_data *)ao;
+ AlsaOutput *ad = (AlsaOutput *)ao;
ad->period_position = 0;
@@ -763,20 +792,21 @@ alsa_cancel(struct audio_output *ao)
static void
alsa_close(struct audio_output *ao)
{
- struct alsa_data *ad = (struct alsa_data *)ao;
+ AlsaOutput *ad = (AlsaOutput *)ao;
snd_pcm_close(ad->pcm);
+ g_free(ad->silence);
}
static size_t
alsa_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error)
{
- struct alsa_data *ad = (struct alsa_data *)ao;
+ AlsaOutput *ad = (AlsaOutput *)ao;
assert(size % ad->in_frame_size == 0);
- chunk = pcm_export(&ad->export, chunk, size, &size);
+ chunk = ad->pcm_export->Export(chunk, size, size);
assert(size % ad->out_frame_size == 0);
@@ -789,8 +819,7 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
% ad->period_frames;
size_t bytes_written = ret * ad->out_frame_size;
- return pcm_export_source_size(&ad->export,
- bytes_written);
+ return ad->pcm_export->CalcSourceSize(bytes_written);
}
if (ret < 0 && ret != -EAGAIN && ret != -EINTR &&
@@ -803,17 +832,20 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
}
const struct audio_output_plugin alsa_output_plugin = {
- .name = "alsa",
- .test_default_device = alsa_test_default_device,
- .init = alsa_init,
- .finish = alsa_finish,
- .enable = alsa_output_enable,
- .disable = alsa_output_disable,
- .open = alsa_open,
- .play = alsa_play,
- .drain = alsa_drain,
- .cancel = alsa_cancel,
- .close = alsa_close,
-
- .mixer_plugin = &alsa_mixer_plugin,
+ "alsa",
+ alsa_test_default_device,
+ alsa_init,
+ alsa_finish,
+ alsa_output_enable,
+ alsa_output_disable,
+ alsa_open,
+ alsa_close,
+ nullptr,
+ nullptr,
+ alsa_play,
+ alsa_drain,
+ alsa_cancel,
+ nullptr,
+
+ &alsa_mixer_plugin,
};
diff --git a/src/output/alsa_output_plugin.h b/src/output/AlsaOutputPlugin.hxx
index daa1f3615..dc7e639a8 100644
--- a/src/output/alsa_output_plugin.h
+++ b/src/output/AlsaOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_ALSA_OUTPUT_PLUGIN_H
-#define MPD_ALSA_OUTPUT_PLUGIN_H
+#ifndef MPD_ALSA_OUTPUT_PLUGIN_HXX
+#define MPD_ALSA_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin alsa_output_plugin;
diff --git a/src/output/ao_output_plugin.c b/src/output/AoOutputPlugin.cxx
index d7e577fa4..db7b9a360 100644
--- a/src/output/ao_output_plugin.c
+++ b/src/output/AoOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,28 +18,41 @@
*/
#include "config.h"
-#include "ao_output_plugin.h"
-#include "output_api.h"
+#include "AoOutputPlugin.hxx"
+#include "OutputAPI.hxx"
#include <ao/ao.h>
#include <glib.h>
+#include <string.h>
+
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "ao"
/* An ao_sample_format, with all fields set to zero: */
-static const ao_sample_format OUR_AO_FORMAT_INITIALIZER;
+static ao_sample_format OUR_AO_FORMAT_INITIALIZER;
static unsigned ao_output_ref;
-struct ao_data {
+struct AoOutput {
struct audio_output base;
size_t write_size;
int driver;
ao_option *options;
ao_device *device;
-} AoData;
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &ao_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
+
+ bool Configure(const config_param &param, GError **error_r);
+};
static inline GQuark
ao_output_quark(void)
@@ -81,78 +94,83 @@ ao_output_error(GError **error_r)
"%s", error);
}
-static struct audio_output *
-ao_output_init(const struct config_param *param,
- GError **error)
+inline bool
+AoOutput::Configure(const config_param &param, GError **error_r)
{
- struct ao_data *ad = g_new(struct ao_data, 1);
-
- if (!ao_base_init(&ad->base, &ao_output_plugin, param, error)) {
- g_free(ad);
- return NULL;
- }
-
- ao_info *ai;
const char *value;
- ad->options = NULL;
+ options = nullptr;
- ad->write_size = config_get_block_unsigned(param, "write_size", 1024);
+ write_size = param.GetBlockValue("write_size", 1024u);
if (ao_output_ref == 0) {
ao_initialize();
}
ao_output_ref++;
- value = config_get_block_string(param, "driver", "default");
+ value = param.GetBlockValue("driver", "default");
if (0 == strcmp(value, "default"))
- ad->driver = ao_default_driver_id();
+ driver = ao_default_driver_id();
else
- ad->driver = ao_driver_id(value);
+ driver = ao_driver_id(value);
- if (ad->driver < 0) {
- g_set_error(error, ao_output_quark(), 0,
+ if (driver < 0) {
+ g_set_error(error_r, ao_output_quark(), 0,
"\"%s\" is not a valid ao driver",
value);
- ao_base_finish(&ad->base);
- g_free(ad);
- return NULL;
+ return false;
}
- if ((ai = ao_driver_info(ad->driver)) == NULL) {
- g_set_error(error, ao_output_quark(), 0,
+ ao_info *ai = ao_driver_info(driver);
+ if (ai == nullptr) {
+ g_set_error(error_r, ao_output_quark(), 0,
"problems getting driver info");
- ao_base_finish(&ad->base);
- g_free(ad);
- return NULL;
+ return false;
}
g_debug("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
- config_get_block_string(param, "name", NULL));
+ param.GetBlockValue("name", nullptr));
- value = config_get_block_string(param, "options", NULL);
- if (value != NULL) {
- gchar **options = g_strsplit(value, ";", 0);
+ value = param.GetBlockValue("options", nullptr);
+ if (value != nullptr) {
+ gchar **_options = g_strsplit(value, ";", 0);
- for (unsigned i = 0; options[i] != NULL; ++i) {
- gchar **key_value = g_strsplit(options[i], "=", 2);
+ for (unsigned i = 0; _options[i] != nullptr; ++i) {
+ gchar **key_value = g_strsplit(_options[i], "=", 2);
- if (key_value[0] == NULL || key_value[1] == NULL) {
- g_set_error(error, ao_output_quark(), 0,
+ if (key_value[0] == nullptr || key_value[1] == nullptr) {
+ g_set_error(error_r, ao_output_quark(), 0,
"problems parsing options \"%s\"",
- options[i]);
- ao_base_finish(&ad->base);
- g_free(ad);
- return NULL;
+ _options[i]);
+ return false;
}
- ao_append_option(&ad->options, key_value[0],
+ ao_append_option(&options, key_value[0],
key_value[1]);
g_strfreev(key_value);
}
- g_strfreev(options);
+ g_strfreev(_options);
+ }
+
+ return true;
+}
+
+static struct audio_output *
+ao_output_init(const config_param &param, GError **error_r)
+{
+ AoOutput *ad = new AoOutput();
+
+ if (!ad->Initialize(param, error_r)) {
+ delete ad;
+ return nullptr;
+ }
+
+ if (!ad->Configure(param, error_r)) {
+ ad->Deinitialize();
+ delete ad;
+ return nullptr;
}
return &ad->base;
@@ -161,11 +179,11 @@ ao_output_init(const struct config_param *param,
static void
ao_output_finish(struct audio_output *ao)
{
- struct ao_data *ad = (struct ao_data *)ao;
+ AoOutput *ad = (AoOutput *)ao;
ao_free_options(ad->options);
- ao_base_finish(&ad->base);
- g_free(ad);
+ ad->Deinitialize();
+ delete ad;
ao_output_ref--;
@@ -176,24 +194,24 @@ ao_output_finish(struct audio_output *ao)
static void
ao_output_close(struct audio_output *ao)
{
- struct ao_data *ad = (struct ao_data *)ao;
+ AoOutput *ad = (AoOutput *)ao;
ao_close(ad->device);
}
static bool
-ao_output_open(struct audio_output *ao, struct audio_format *audio_format,
+ao_output_open(struct audio_output *ao, AudioFormat &audio_format,
GError **error)
{
ao_sample_format format = OUR_AO_FORMAT_INITIALIZER;
- struct ao_data *ad = (struct ao_data *)ao;
+ AoOutput *ad = (AoOutput *)ao;
- switch (audio_format->format) {
- case SAMPLE_FORMAT_S8:
+ switch (audio_format.format) {
+ case SampleFormat::S8:
format.bits = 8;
break;
- case SAMPLE_FORMAT_S16:
+ case SampleFormat::S16:
format.bits = 16;
break;
@@ -201,18 +219,18 @@ ao_output_open(struct audio_output *ao, struct audio_format *audio_format,
/* support for 24 bit samples in libao is currently
dubious, and until we have sorted that out,
convert everything to 16 bit */
- audio_format->format = SAMPLE_FORMAT_S16;
+ audio_format.format = SampleFormat::S16;
format.bits = 16;
break;
}
- format.rate = audio_format->sample_rate;
+ format.rate = audio_format.sample_rate;
format.byte_format = AO_FMT_NATIVE;
- format.channels = audio_format->channels;
+ format.channels = audio_format.channels;
ad->device = ao_open_live(ad->driver, &format, ad->options);
- if (ad->device == NULL) {
+ if (ad->device == nullptr) {
ao_output_error(error);
return false;
}
@@ -230,7 +248,7 @@ static int ao_play_deconst(ao_device *device, const void *output_samples,
{
union {
const void *in;
- void *out;
+ char *out;
} u;
u.in = output_samples;
@@ -241,7 +259,7 @@ static size_t
ao_output_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error)
{
- struct ao_data *ad = (struct ao_data *)ao;
+ AoOutput *ad = (AoOutput *)ao;
if (size > ad->write_size)
size = ad->write_size;
@@ -255,10 +273,19 @@ ao_output_play(struct audio_output *ao, const void *chunk, size_t size,
}
const struct audio_output_plugin ao_output_plugin = {
- .name = "ao",
- .init = ao_output_init,
- .finish = ao_output_finish,
- .open = ao_output_open,
- .close = ao_output_close,
- .play = ao_output_play,
+ "ao",
+ nullptr,
+ ao_output_init,
+ ao_output_finish,
+ nullptr,
+ nullptr,
+ ao_output_open,
+ ao_output_close,
+ nullptr,
+ nullptr,
+ ao_output_play,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
};
diff --git a/src/output/ao_output_plugin.h b/src/output/AoOutputPlugin.hxx
index 9a3a47c05..a44885e56 100644
--- a/src/output/ao_output_plugin.h
+++ b/src/output/AoOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_AO_OUTPUT_PLUGIN_H
-#define MPD_AO_OUTPUT_PLUGIN_H
+#ifndef MPD_AO_OUTPUT_PLUGIN_HXX
+#define MPD_AO_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin ao_output_plugin;
diff --git a/src/output/fifo_output_plugin.c b/src/output/FifoOutputPlugin.cxx
index 022be0b4a..50062988c 100644
--- a/src/output/fifo_output_plugin.c
+++ b/src/output/FifoOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,10 +18,9 @@
*/
#include "config.h"
-#include "fifo_output_plugin.h"
-#include "output_api.h"
-#include "utils.h"
-#include "timer.h"
+#include "FifoOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "Timer.hxx"
#include "fd_util.h"
#include "open.h"
@@ -38,14 +37,37 @@
#define FIFO_BUFFER_SIZE 65536 /* pipe capacity on Linux >= 2.6.11 */
-struct fifo_data {
+struct FifoOutput {
struct audio_output base;
char *path;
int input;
int output;
bool created;
- struct timer *timer;
+ Timer *timer;
+
+ FifoOutput()
+ :path(nullptr), input(-1), output(-1), created(false) {}
+
+ ~FifoOutput() {
+ g_free(path);
+ }
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &fifo_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
+
+ bool Create(GError **error_r);
+ bool Check(GError **error_r);
+ void Delete();
+
+ bool Open(GError **error_r);
+ void Close();
};
/**
@@ -57,156 +79,138 @@ fifo_output_quark(void)
return g_quark_from_static_string("fifo_output");
}
-static struct fifo_data *fifo_data_new(void)
-{
- struct fifo_data *ret;
-
- ret = g_new(struct fifo_data, 1);
-
- ret->path = NULL;
- ret->input = -1;
- ret->output = -1;
- ret->created = false;
-
- return ret;
-}
-
-static void fifo_data_free(struct fifo_data *fd)
+inline void
+FifoOutput::Delete()
{
- g_free(fd->path);
- g_free(fd);
-}
-
-static void fifo_delete(struct fifo_data *fd)
-{
- g_debug("Removing FIFO \"%s\"", fd->path);
+ g_debug("Removing FIFO \"%s\"", path);
- if (unlink(fd->path) < 0) {
+ if (unlink(path) < 0) {
g_warning("Could not remove FIFO \"%s\": %s",
- fd->path, g_strerror(errno));
+ path, g_strerror(errno));
return;
}
- fd->created = false;
+ created = false;
}
-static void
-fifo_close(struct fifo_data *fd)
+void
+FifoOutput::Close()
{
struct stat st;
- if (fd->input >= 0) {
- close(fd->input);
- fd->input = -1;
+ if (input >= 0) {
+ close(input);
+ input = -1;
}
- if (fd->output >= 0) {
- close(fd->output);
- fd->output = -1;
+ if (output >= 0) {
+ close(output);
+ output = -1;
}
- if (fd->created && (stat(fd->path, &st) == 0))
- fifo_delete(fd);
+ if (created && (stat(path, &st) == 0))
+ Delete();
}
-static bool
-fifo_make(struct fifo_data *fd, GError **error)
+inline bool
+FifoOutput::Create(GError **error_r)
{
- if (mkfifo(fd->path, 0666) < 0) {
- g_set_error(error, fifo_output_quark(), errno,
+ if (mkfifo(path, 0666) < 0) {
+ g_set_error(error_r, fifo_output_quark(), errno,
"Couldn't create FIFO \"%s\": %s",
- fd->path, g_strerror(errno));
+ path, g_strerror(errno));
return false;
}
- fd->created = true;
-
+ created = true;
return true;
}
-static bool
-fifo_check(struct fifo_data *fd, GError **error)
+inline bool
+FifoOutput::Check(GError **error_r)
{
struct stat st;
-
- if (stat(fd->path, &st) < 0) {
+ if (stat(path, &st) < 0) {
if (errno == ENOENT) {
/* Path doesn't exist */
- return fifo_make(fd, error);
+ return Create(error_r);
}
- g_set_error(error, fifo_output_quark(), errno,
+ g_set_error(error_r, fifo_output_quark(), errno,
"Failed to stat FIFO \"%s\": %s",
- fd->path, g_strerror(errno));
+ path, g_strerror(errno));
return false;
}
if (!S_ISFIFO(st.st_mode)) {
- g_set_error(error, fifo_output_quark(), 0,
+ g_set_error(error_r, fifo_output_quark(), 0,
"\"%s\" already exists, but is not a FIFO",
- fd->path);
+ path);
return false;
}
return true;
}
-static bool
-fifo_open(struct fifo_data *fd, GError **error)
+inline bool
+FifoOutput::Open(GError **error_r)
{
- if (!fifo_check(fd, error))
+ if (!Check(error_r))
return false;
- fd->input = open_cloexec(fd->path, O_RDONLY|O_NONBLOCK|O_BINARY, 0);
- if (fd->input < 0) {
- g_set_error(error, fifo_output_quark(), errno,
+ input = open_cloexec(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",
- fd->path, g_strerror(errno));
- fifo_close(fd);
+ path, g_strerror(errno));
+ Close();
return false;
}
- fd->output = open_cloexec(fd->path, O_WRONLY|O_NONBLOCK|O_BINARY, 0);
- if (fd->output < 0) {
- g_set_error(error, fifo_output_quark(), errno,
+ output = open_cloexec(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",
- fd->path, g_strerror(errno));
- fifo_close(fd);
+ path, g_strerror(errno));
+ Close();
return false;
}
return true;
}
-static struct audio_output *
-fifo_output_init(const struct config_param *param,
- GError **error_r)
+static bool
+fifo_open(FifoOutput *fd, GError **error_r)
{
- struct fifo_data *fd;
+ return fd->Open(error_r);
+}
- GError *error = NULL;
- char *path = config_dup_block_path(param, "path", &error);
+static struct audio_output *
+fifo_output_init(const config_param &param, GError **error_r)
+{
+ GError *error = nullptr;
+ char *path = param.DupBlockPath("path", &error);
if (!path) {
- if (error != NULL)
+ if (error != nullptr)
g_propagate_error(error_r, error);
else
g_set_error(error_r, fifo_output_quark(), 0,
"No \"path\" parameter specified");
- return NULL;
+ return nullptr;
}
- fd = fifo_data_new();
+ FifoOutput *fd = new FifoOutput();
fd->path = path;
- if (!ao_base_init(&fd->base, &fifo_output_plugin, param, error_r)) {
- fifo_data_free(fd);
- return NULL;
+ if (!fd->Initialize(param, error_r)) {
+ delete fd;
+ return nullptr;
}
if (!fifo_open(fd, error_r)) {
- ao_base_finish(&fd->base);
- fifo_data_free(fd);
- return NULL;
+ fd->Deinitialize();
+ delete fd;
+ return nullptr;
}
return &fd->base;
@@ -215,20 +219,20 @@ fifo_output_init(const struct config_param *param,
static void
fifo_output_finish(struct audio_output *ao)
{
- struct fifo_data *fd = (struct fifo_data *)ao;
+ FifoOutput *fd = (FifoOutput *)ao;
- fifo_close(fd);
- ao_base_finish(&fd->base);
- fifo_data_free(fd);
+ fd->Close();
+ fd->Deinitialize();
+ delete fd;
}
static bool
-fifo_output_open(struct audio_output *ao, struct audio_format *audio_format,
+fifo_output_open(struct audio_output *ao, AudioFormat &audio_format,
G_GNUC_UNUSED GError **error)
{
- struct fifo_data *fd = (struct fifo_data *)ao;
+ FifoOutput *fd = (FifoOutput *)ao;
- fd->timer = timer_new(audio_format);
+ fd->timer = new Timer(audio_format);
return true;
}
@@ -236,19 +240,19 @@ fifo_output_open(struct audio_output *ao, struct audio_format *audio_format,
static void
fifo_output_close(struct audio_output *ao)
{
- struct fifo_data *fd = (struct fifo_data *)ao;
+ FifoOutput *fd = (FifoOutput *)ao;
- timer_free(fd->timer);
+ delete fd->timer;
}
static void
fifo_output_cancel(struct audio_output *ao)
{
- struct fifo_data *fd = (struct fifo_data *)ao;
+ FifoOutput *fd = (FifoOutput *)ao;
char buf[FIFO_BUFFER_SIZE];
int bytes = 1;
- timer_reset(fd->timer);
+ fd->timer->Reset();
while (bytes > 0 && errno != EINTR)
bytes = read(fd->input, buf, FIFO_BUFFER_SIZE);
@@ -262,10 +266,10 @@ fifo_output_cancel(struct audio_output *ao)
static unsigned
fifo_output_delay(struct audio_output *ao)
{
- struct fifo_data *fd = (struct fifo_data *)ao;
+ FifoOutput *fd = (FifoOutput *)ao;
- return fd->timer->started
- ? timer_delay(fd->timer)
+ return fd->timer->IsStarted()
+ ? fd->timer->GetDelay()
: 0;
}
@@ -273,12 +277,12 @@ static size_t
fifo_output_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error)
{
- struct fifo_data *fd = (struct fifo_data *)ao;
+ FifoOutput *fd = (FifoOutput *)ao;
ssize_t bytes;
- if (!fd->timer->started)
- timer_start(fd->timer);
- timer_add(fd->timer, size);
+ if (!fd->timer->IsStarted())
+ fd->timer->Start();
+ fd->timer->Add(size);
while (true) {
bytes = write(fd->output, chunk, size);
@@ -304,12 +308,19 @@ fifo_output_play(struct audio_output *ao, const void *chunk, size_t size,
}
const struct audio_output_plugin fifo_output_plugin = {
- .name = "fifo",
- .init = fifo_output_init,
- .finish = fifo_output_finish,
- .open = fifo_output_open,
- .close = fifo_output_close,
- .delay = fifo_output_delay,
- .play = fifo_output_play,
- .cancel = fifo_output_cancel,
+ "fifo",
+ nullptr,
+ fifo_output_init,
+ fifo_output_finish,
+ nullptr,
+ nullptr,
+ fifo_output_open,
+ fifo_output_close,
+ fifo_output_delay,
+ nullptr,
+ fifo_output_play,
+ nullptr,
+ fifo_output_cancel,
+ nullptr,
+ nullptr,
};
diff --git a/src/output/fifo_output_plugin.h b/src/output/FifoOutputPlugin.hxx
index 85f7985e1..dca2886d8 100644
--- a/src/output/fifo_output_plugin.h
+++ b/src/output/FifoOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_FIFO_OUTPUT_PLUGIN_H
-#define MPD_FIFO_OUTPUT_PLUGIN_H
+#ifndef MPD_FIFO_OUTPUT_PLUGIN_HXX
+#define MPD_FIFO_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin fifo_output_plugin;
diff --git a/src/output/HttpdClient.cxx b/src/output/HttpdClient.cxx
new file mode 100644
index 000000000..0a00ee2f9
--- /dev/null
+++ b/src/output/HttpdClient.cxx
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "HttpdClient.hxx"
+#include "HttpdInternal.hxx"
+#include "util/fifo_buffer.h"
+#include "Page.hxx"
+#include "IcyMetaDataServer.hxx"
+#include "SocketError.hxx"
+
+#include <assert.h>
+#include <string.h>
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "httpd_output"
+
+HttpdClient::~HttpdClient()
+{
+ if (state == RESPONSE) {
+ if (current_page != nullptr)
+ current_page->Unref();
+
+ for (auto page : pages)
+ page->Unref();
+ }
+
+ if (metadata)
+ metadata->Unref();
+}
+
+void
+HttpdClient::Close()
+{
+ httpd->RemoveClient(*this);
+}
+
+void
+HttpdClient::LockClose()
+{
+ const ScopeLock protect(httpd->mutex);
+ Close();
+}
+
+void
+HttpdClient::BeginResponse()
+{
+ assert(state != RESPONSE);
+
+ state = RESPONSE;
+ current_page = nullptr;
+
+ httpd->SendHeader(*this);
+}
+
+/**
+ * Handle a line of the HTTP request.
+ */
+bool
+HttpdClient::HandleLine(const char *line)
+{
+ assert(state != RESPONSE);
+
+ if (state == REQUEST) {
+ if (strncmp(line, "GET /", 5) != 0) {
+ /* only GET is supported */
+ g_warning("malformed request line from client");
+ return false;
+ }
+
+ line = strchr(line + 5, ' ');
+ if (line == nullptr || strncmp(line + 1, "HTTP/", 5) != 0) {
+ /* HTTP/0.9 without request headers */
+ BeginResponse();
+ return true;
+ }
+
+ /* after the request line, request headers follow */
+ state = HEADERS;
+ return true;
+ } else {
+ if (*line == 0) {
+ /* empty line: request is finished */
+ BeginResponse();
+ return true;
+ }
+
+ if (g_ascii_strncasecmp(line, "Icy-MetaData: 1", 15) == 0) {
+ /* Send icy metadata */
+ metadata_requested = metadata_supported;
+ return true;
+ }
+
+ if (g_ascii_strncasecmp(line, "transferMode.dlna.org: Streaming", 32) == 0) {
+ /* Send as dlna */
+ dlna_streaming_requested = true;
+ /* metadata is not supported by dlna streaming, so disable it */
+ metadata_supported = false;
+ metadata_requested = false;
+ return true;
+ }
+
+ /* expect more request headers */
+ return true;
+ }
+}
+
+/**
+ * Sends the status line and response headers to the client.
+ */
+bool
+HttpdClient::SendResponse()
+{
+ char buffer[1024];
+ assert(state == RESPONSE);
+
+ if (dlna_streaming_requested) {
+ g_snprintf(buffer, sizeof(buffer),
+ "HTTP/1.1 206 OK\r\n"
+ "Content-Type: %s\r\n"
+ "Content-Length: 10000\r\n"
+ "Content-RangeX: 0-1000000/1000000\r\n"
+ "transferMode.dlna.org: Streaming\r\n"
+ "Accept-Ranges: bytes\r\n"
+ "Connection: close\r\n"
+ "realTimeInfo.dlna.org: DLNA.ORG_TLAG=*\r\n"
+ "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0\r\n"
+ "\r\n",
+ httpd->content_type);
+
+ } else if (metadata_requested) {
+ gchar *metadata_header;
+
+ metadata_header =
+ icy_server_metadata_header(httpd->name, httpd->genre,
+ httpd->website,
+ httpd->content_type,
+ metaint);
+
+ g_strlcpy(buffer, metadata_header, sizeof(buffer));
+
+ g_free(metadata_header);
+
+ } else { /* revert to a normal HTTP request */
+ g_snprintf(buffer, sizeof(buffer),
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: %s\r\n"
+ "Connection: close\r\n"
+ "Pragma: no-cache\r\n"
+ "Cache-Control: no-cache, no-store\r\n"
+ "\r\n",
+ httpd->content_type);
+ }
+
+ ssize_t nbytes = SocketMonitor::Write(buffer, strlen(buffer));
+ if (gcc_unlikely(nbytes < 0)) {
+ const SocketErrorMessage msg;
+ g_warning("failed to write to client: %s", (const char *)msg);
+ Close();
+ return false;
+ }
+
+ return true;
+}
+
+HttpdClient::HttpdClient(HttpdOutput *_httpd, int _fd, EventLoop &_loop,
+ bool _metadata_supported)
+ :BufferedSocket(_fd, _loop),
+ httpd(_httpd),
+ state(REQUEST),
+ dlna_streaming_requested(false),
+ metadata_supported(_metadata_supported),
+ metadata_requested(false), metadata_sent(true),
+ metaint(8192), /*TODO: just a std value */
+ metadata(nullptr),
+ metadata_current_position(0), metadata_fill(0)
+{
+}
+
+size_t
+HttpdClient::GetQueueSize() const
+{
+ if (state != RESPONSE)
+ return 0;
+
+ size_t size = 0;
+ for (auto page : pages)
+ size += page->size;
+ return size;
+}
+
+void
+HttpdClient::CancelQueue()
+{
+ if (state != RESPONSE)
+ return;
+
+ for (auto page : pages)
+ page->Unref();
+ pages.clear();
+
+ if (current_page == nullptr)
+ CancelWrite();
+}
+
+ssize_t
+HttpdClient::TryWritePage(const Page &page, size_t position)
+{
+ assert(position < page.size);
+
+ return Write(page.data + position, page.size - position);
+}
+
+ssize_t
+HttpdClient::TryWritePageN(const Page &page, size_t position, ssize_t n)
+{
+ return n >= 0
+ ? Write(page.data + position, n)
+ : TryWritePage(page, position);
+}
+
+ssize_t
+HttpdClient::GetBytesTillMetaData() const
+{
+ if (metadata_requested &&
+ current_page->size - current_position > metaint - metadata_fill)
+ return metaint - metadata_fill;
+
+ return -1;
+}
+
+inline bool
+HttpdClient::TryWrite()
+{
+ const ScopeLock protect(httpd->mutex);
+
+ assert(state == RESPONSE);
+
+ if (current_page == nullptr) {
+ if (pages.empty()) {
+ /* another thread has removed the event source
+ while this thread was waiting for
+ httpd->mutex */
+ CancelWrite();
+ return true;
+ }
+
+ current_page = pages.front();
+ pages.pop_front();
+ current_position = 0;
+ }
+
+ const ssize_t bytes_to_write = GetBytesTillMetaData();
+ if (bytes_to_write == 0) {
+ if (!metadata_sent) {
+ ssize_t nbytes = TryWritePage(*metadata,
+ metadata_current_position);
+ if (nbytes < 0) {
+ auto e = GetSocketError();
+ if (IsSocketErrorAgain(e))
+ return true;
+
+ if (!IsSocketErrorClosed(e)) {
+ SocketErrorMessage msg(e);
+ g_warning("failed to write to client: %s",
+ (const char *)msg);
+ }
+
+ Close();
+ return false;
+ }
+
+ metadata_current_position += nbytes;
+
+ if (metadata->size - metadata_current_position == 0) {
+ metadata_fill = 0;
+ metadata_current_position = 0;
+ metadata_sent = true;
+ }
+ } else {
+ guchar empty_data = 0;
+
+ ssize_t nbytes = Write(&empty_data, 1);
+ if (nbytes < 0) {
+ auto e = GetSocketError();
+ if (IsSocketErrorAgain(e))
+ return true;
+
+ if (!IsSocketErrorClosed(e)) {
+ SocketErrorMessage msg(e);
+ g_warning("failed to write to client: %s",
+ (const char *)msg);
+ }
+
+ Close();
+ return false;
+ }
+
+ metadata_fill = 0;
+ metadata_current_position = 0;
+ }
+ } else {
+ ssize_t nbytes =
+ TryWritePageN(*current_page, current_position,
+ bytes_to_write);
+ if (nbytes < 0) {
+ auto e = GetSocketError();
+ if (IsSocketErrorAgain(e))
+ return true;
+
+ if (!IsSocketErrorClosed(e)) {
+ SocketErrorMessage msg(e);
+ g_warning("failed to write to client: %s",
+ (const char *)msg);
+ }
+
+ Close();
+ return false;
+ }
+
+ current_position += nbytes;
+ assert(current_position <= current_page->size);
+
+ if (metadata_requested)
+ metadata_fill += nbytes;
+
+ if (current_position >= current_page->size) {
+ current_page->Unref();
+ current_page = nullptr;
+
+ if (pages.empty())
+ /* all pages are sent: remove the
+ event source */
+ CancelWrite();
+ }
+ }
+
+ return true;
+}
+
+void
+HttpdClient::PushPage(Page *page)
+{
+ if (state != RESPONSE)
+ /* the client is still writing the HTTP request */
+ return;
+
+ page->Ref();
+ pages.push_back(page);
+
+ ScheduleWrite();
+}
+
+void
+HttpdClient::PushMetaData(Page *page)
+{
+ if (metadata) {
+ metadata->Unref();
+ metadata = nullptr;
+ }
+
+ g_return_if_fail (page);
+
+ page->Ref();
+ metadata = page;
+ metadata_sent = false;
+}
+
+bool
+HttpdClient::OnSocketReady(unsigned flags)
+{
+ if (!BufferedSocket::OnSocketReady(flags))
+ return false;
+
+ if (flags & WRITE)
+ if (!TryWrite())
+ return false;
+
+ return true;
+}
+
+BufferedSocket::InputResult
+HttpdClient::OnSocketInput(const void *data, size_t length)
+{
+ if (state == RESPONSE) {
+ g_warning("unexpected input from client");
+ LockClose();
+ return InputResult::CLOSED;
+ }
+
+ const char *line = (const char *)data;
+ const char *newline = (const char *)memchr(line, '\n', length);
+ if (newline == nullptr)
+ return InputResult::MORE;
+
+ ConsumeInput(newline + 1 - line);
+
+ if (newline > line && newline[-1] == '\r')
+ --newline;
+
+ /* terminate the string at the end of the line; the const_cast
+ is a dirty hack */
+ *const_cast<char *>(newline) = 0;
+
+ if (!HandleLine(line)) {
+ assert(state == RESPONSE);
+ LockClose();
+ return InputResult::CLOSED;
+ }
+
+ if (state == RESPONSE && !SendResponse())
+ return InputResult::CLOSED;
+
+ return InputResult::AGAIN;
+}
+
+void
+HttpdClient::OnSocketError(GError *error)
+{
+ g_warning("error on HTTP client: %s", error->message);
+ g_error_free(error);
+}
+
+void
+HttpdClient::OnSocketClosed()
+{
+ LockClose();
+}
diff --git a/src/output/HttpdClient.hxx b/src/output/HttpdClient.hxx
new file mode 100644
index 000000000..46196d2e3
--- /dev/null
+++ b/src/output/HttpdClient.hxx
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_OUTPUT_HTTPD_CLIENT_HXX
+#define MPD_OUTPUT_HTTPD_CLIENT_HXX
+
+#include "event/BufferedSocket.hxx"
+#include "gcc.h"
+
+#include <list>
+
+#include <stddef.h>
+
+struct HttpdOutput;
+class Page;
+
+class HttpdClient final : public BufferedSocket {
+ /**
+ * The httpd output object this client is connected to.
+ */
+ HttpdOutput *const httpd;
+
+ /**
+ * The current state of the client.
+ */
+ enum {
+ /** reading the request line */
+ REQUEST,
+
+ /** reading the request headers */
+ HEADERS,
+
+ /** sending the HTTP response */
+ RESPONSE,
+ } state;
+
+ /**
+ * A queue of #Page objects to be sent to the client.
+ */
+ std::list<Page *> pages;
+
+ /**
+ * The #page which is currently being sent to the client.
+ */
+ Page *current_page;
+
+ /**
+ * The amount of bytes which were already sent from
+ * #current_page.
+ */
+ size_t current_position;
+
+ /**
+ * If DLNA streaming was an option.
+ */
+ bool dlna_streaming_requested;
+
+ /* ICY */
+
+ /**
+ * Do we support sending Icy-Metadata to the client? This is
+ * disabled if the httpd audio output uses encoder tags.
+ */
+ bool metadata_supported;
+
+ /**
+ * If we should sent icy metadata.
+ */
+ bool metadata_requested;
+
+ /**
+ * If the current metadata was already sent to the client.
+ */
+ bool metadata_sent;
+
+ /**
+ * The amount of streaming data between each metadata block
+ */
+ guint metaint;
+
+ /**
+ * The metadata as #Page which is currently being sent to the client.
+ */
+ Page *metadata;
+
+ /*
+ * The amount of bytes which were already sent from the metadata.
+ */
+ size_t metadata_current_position;
+
+ /**
+ * The amount of streaming data sent to the client
+ * since the last icy information was sent.
+ */
+ guint metadata_fill;
+
+public:
+ /**
+ * @param httpd the HTTP output device
+ * @param fd the socket file descriptor
+ */
+ HttpdClient(HttpdOutput *httpd, int _fd, EventLoop &_loop,
+ bool _metadata_supported);
+
+ /**
+ * Note: this does not remove the client from the
+ * #HttpdOutput object.
+ */
+ ~HttpdClient();
+
+ /**
+ * Frees the client and removes it from the server's client list.
+ */
+ void Close();
+
+ void LockClose();
+
+ /**
+ * Returns the total size of this client's page queue.
+ */
+ gcc_pure
+ size_t GetQueueSize() const;
+
+ /**
+ * Clears the page queue.
+ */
+ void CancelQueue();
+
+ /**
+ * Handle a line of the HTTP request.
+ */
+ bool HandleLine(const char *line);
+
+ /**
+ * Switch the client to the "RESPONSE" state.
+ */
+ void BeginResponse();
+
+ /**
+ * Sends the status line and response headers to the client.
+ */
+ bool SendResponse();
+
+ gcc_pure
+ ssize_t GetBytesTillMetaData() const;
+
+ ssize_t TryWritePage(const Page &page, size_t position);
+ ssize_t TryWritePageN(const Page &page, size_t position, ssize_t n);
+
+ bool TryWrite();
+
+ /**
+ * Appends a page to the client's queue.
+ */
+ void PushPage(Page *page);
+
+ /**
+ * Sends the passed metadata.
+ */
+ void PushMetaData(Page *page);
+
+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 OnSocketClosed() override;
+};
+
+#endif
diff --git a/src/output/httpd_internal.h b/src/output/HttpdInternal.hxx
index 5dcb8ab9b..e8a37e033 100644
--- a/src/output/httpd_internal.h
+++ b/src/output/HttpdInternal.hxx
@@ -25,16 +25,22 @@
#ifndef MPD_OUTPUT_HTTPD_INTERNAL_H
#define MPD_OUTPUT_HTTPD_INTERNAL_H
-#include "output_internal.h"
-#include "timer.h"
-
-#include <glib.h>
-
-#include <stdbool.h>
-
-struct httpd_client;
-
-struct httpd_output {
+#include "OutputInternal.hxx"
+#include "Timer.hxx"
+#include "thread/Mutex.hxx"
+#include "event/ServerSocket.hxx"
+
+#include <forward_list>
+
+struct config_param;
+class EventLoop;
+class ServerSocket;
+class HttpdClient;
+class Page;
+struct Encoder;
+struct Tag;
+
+struct HttpdOutput final : private ServerSocket {
struct audio_output base;
/**
@@ -46,7 +52,7 @@ struct httpd_output {
/**
* The configured encoder plugin.
*/
- struct encoder *encoder;
+ Encoder *encoder;
/**
* Number of bytes which were fed into the encoder, without
@@ -65,28 +71,23 @@ struct httpd_output {
* This mutex protects the listener socket and the client
* list.
*/
- GMutex *mutex;
+ mutable Mutex mutex;
/**
- * A #timer object to synchronize this output with the
+ * A #Timer object to synchronize this output with the
* wallclock.
*/
- struct timer *timer;
-
- /**
- * The listener socket.
- */
- struct server_socket *server_socket;
+ Timer *timer;
/**
* The header page, which is sent to every client on connect.
*/
- struct page *header;
+ Page *header;
/**
* The metadata, which is sent to every client.
*/
- struct page *metadata;
+ Page *metadata;
/**
* The configured name.
@@ -105,7 +106,7 @@ struct httpd_output {
* A linked list containing all clients which are currently
* connected.
*/
- GList *clients;
+ std::forward_list<HttpdClient> clients;
/**
* A temporary buffer for the httpd_output_read_page()
@@ -118,21 +119,88 @@ struct httpd_output {
* at the same time.
*/
guint clients_max, clients_cnt;
-};
-/**
- * Removes a client from the httpd_output.clients linked list.
- */
-void
-httpd_output_remove_client(struct httpd_output *httpd,
- struct httpd_client *client);
+ HttpdOutput(EventLoop &_loop);
+ ~HttpdOutput();
-/**
- * Sends the encoder header to the client. This is called right after
- * the response headers have been sent.
- */
-void
-httpd_output_send_header(struct httpd_output *httpd,
- struct httpd_client *client);
+ bool Configure(const config_param &param, GError **error_r);
+
+ bool Bind(GError **error_r);
+ void Unbind();
+
+ /**
+ * Caller must lock the mutex.
+ */
+ bool OpenEncoder(AudioFormat &audio_format,
+ GError **error_r);
+
+ /**
+ * Caller must lock the mutex.
+ */
+ bool Open(AudioFormat &audio_format, GError **error_r);
+
+ /**
+ * Caller must lock the mutex.
+ */
+ void Close();
+
+ /**
+ * Check whether there is at least one client.
+ *
+ * Caller must lock the mutex.
+ */
+ gcc_pure
+ bool HasClients() const {
+ return !clients.empty();
+ }
+
+ /**
+ * Check whether there is at least one client.
+ */
+ gcc_pure
+ bool LockHasClients() const {
+ const ScopeLock protect(mutex);
+ return HasClients();
+ }
+
+ void AddClient(int fd);
+
+ /**
+ * Removes a client from the httpd_output.clients linked list.
+ */
+ void RemoveClient(HttpdClient &client);
+
+ /**
+ * Sends the encoder header to the client. This is called
+ * right after the response headers have been sent.
+ */
+ void SendHeader(HttpdClient &client) const;
+
+ /**
+ * Reads data from the encoder (as much as available) and
+ * returns it as a new #page object.
+ */
+ Page *ReadPage();
+
+ /**
+ * Broadcasts a page struct to all clients.
+ *
+ * Mutext must not be locked.
+ */
+ void BroadcastPage(Page *page);
+
+ /**
+ * Broadcasts data from the encoder to all clients.
+ */
+ void BroadcastFromEncoder();
+
+ bool EncodeAndPlay(const void *chunk, size_t size, GError **error_r);
+
+ void SendTag(const Tag *tag);
+
+private:
+ virtual void OnAccept(int fd, const sockaddr &address,
+ size_t address_length, int uid) override;
+};
#endif
diff --git a/src/output/HttpdOutputPlugin.cxx b/src/output/HttpdOutputPlugin.cxx
new file mode 100644
index 000000000..4169aabfa
--- /dev/null
+++ b/src/output/HttpdOutputPlugin.cxx
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "HttpdOutputPlugin.hxx"
+#include "HttpdInternal.hxx"
+#include "HttpdClient.hxx"
+#include "OutputAPI.hxx"
+#include "EncoderPlugin.hxx"
+#include "EncoderList.hxx"
+#include "resolver.h"
+#include "Page.hxx"
+#include "IcyMetaDataServer.hxx"
+#include "fd_util.h"
+#include "Main.hxx"
+
+#include <assert.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBWRAP
+#include <sys/socket.h> /* needed for AF_UNIX */
+#include <tcpd.h>
+#endif
+
+#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");
+}
+
+inline
+HttpdOutput::HttpdOutput(EventLoop &_loop)
+ :ServerSocket(_loop),
+ encoder(nullptr), unflushed_input(0),
+ metadata(nullptr)
+{
+}
+
+HttpdOutput::~HttpdOutput()
+{
+ if (metadata != nullptr)
+ metadata->Unref();
+
+ if (encoder != nullptr)
+ encoder_finish(encoder);
+
+}
+
+inline bool
+HttpdOutput::Bind(GError **error_r)
+{
+ open = false;
+
+ const ScopeLock protect(mutex);
+ return ServerSocket::Open(error_r);
+}
+
+inline void
+HttpdOutput::Unbind()
+{
+ assert(!open);
+
+ const ScopeLock protect(mutex);
+ ServerSocket::Close();
+}
+
+inline bool
+HttpdOutput::Configure(const config_param &param, GError **error_r)
+{
+ /* read configuration */
+ name = param.GetBlockValue("name", "Set name in config");
+ genre = param.GetBlockValue("genre", "Set genre in config");
+ website = param.GetBlockValue("website", "Set website in config");
+
+ guint port = param.GetBlockValue("port", 8000u);
+
+ const char *encoder_name =
+ 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);
+ return false;
+ }
+
+ clients_max = param.GetBlockValue("max_clients", 0u);
+
+ /* set up bind_to_address */
+
+ 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);
+ if (!success)
+ return false;
+
+ /* initialize encoder */
+
+ encoder = encoder_init(*encoder_plugin, param, error_r);
+ if (encoder == nullptr)
+ return false;
+
+ /* determine content type */
+ content_type = encoder_get_mime_type(encoder);
+ if (content_type == nullptr)
+ content_type = "application/octet-stream";
+
+ return true;
+}
+
+static struct audio_output *
+httpd_output_init(const struct config_param &param,
+ GError **error_r)
+{
+ HttpdOutput *httpd = new HttpdOutput(*main_loop);
+
+ if (!ao_base_init(&httpd->base, &httpd_output_plugin, param,
+ error_r)) {
+ delete httpd;
+ return nullptr;
+ }
+
+ if (!httpd->Configure(param, error_r)) {
+ ao_base_finish(&httpd->base);
+ delete httpd;
+ return nullptr;
+ }
+
+ return &httpd->base;
+}
+
+#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#endif
+
+static inline constexpr HttpdOutput *
+Cast(audio_output *ao)
+{
+ return (HttpdOutput *)((char *)ao - offsetof(HttpdOutput, base));
+}
+
+#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+static void
+httpd_output_finish(struct audio_output *ao)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ ao_base_finish(&httpd->base);
+ delete httpd;
+}
+
+/**
+ * Creates a new #HttpdClient object and adds it into the
+ * HttpdOutput.clients linked list.
+ */
+inline void
+HttpdOutput::AddClient(int fd)
+{
+ clients.emplace_front(this, fd, GetEventLoop(),
+ encoder->plugin.tag == nullptr);
+ ++clients_cnt;
+
+ /* pass metadata to client */
+ if (metadata != nullptr)
+ clients.front().PushMetaData(metadata);
+}
+
+void
+HttpdOutput::OnAccept(int fd, const sockaddr &address,
+ size_t address_length, gcc_unused int uid)
+{
+ /* the listener socket has become readable - a client has
+ connected */
+
+#ifdef HAVE_LIBWRAP
+ if (address.sa_family != AF_UNIX) {
+ char *hostaddr = sockaddr_to_string(&address, address_length, NULL);
+ const char *progname = g_get_prgname();
+
+ struct request_info req;
+ request_init(&req, RQ_FILE, fd, RQ_DAEMON, progname, 0);
+
+ fromhost(&req);
+
+ if (!hosts_access(&req)) {
+ /* tcp wrappers says no */
+ g_warning("libwrap refused connection (libwrap=%s) from %s",
+ progname, hostaddr);
+ g_free(hostaddr);
+ close_socket(fd);
+ return;
+ }
+
+ g_free(hostaddr);
+ }
+#else
+ (void)address;
+ (void)address_length;
+#endif /* HAVE_WRAP */
+
+ const ScopeLock protect(mutex);
+
+ if (fd >= 0) {
+ /* can we allow additional client */
+ if (open && (clients_max == 0 || clients_cnt < clients_max))
+ AddClient(fd);
+ else
+ close_socket(fd);
+ } else if (fd < 0 && errno != EINTR) {
+ g_warning("accept() failed: %s", g_strerror(errno));
+ }
+}
+
+Page *
+HttpdOutput::ReadPage()
+{
+ if (unflushed_input >= 65536) {
+ /* 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);
+ unflushed_input = 0;
+ }
+
+ size_t size = 0;
+ do {
+ size_t nbytes = encoder_read(encoder,
+ buffer + size,
+ sizeof(buffer) - size);
+ if (nbytes == 0)
+ break;
+
+ unflushed_input = 0;
+
+ size += nbytes;
+ } while (size < sizeof(buffer));
+
+ if (size == 0)
+ return NULL;
+
+ return Page::Copy(buffer, size);
+}
+
+static bool
+httpd_output_enable(struct audio_output *ao, GError **error_r)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ return httpd->Bind(error_r);
+}
+
+static void
+httpd_output_disable(struct audio_output *ao)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ httpd->Unbind();
+}
+
+inline bool
+HttpdOutput::OpenEncoder(AudioFormat &audio_format, GError **error)
+{
+ if (!encoder_open(encoder, audio_format, error))
+ return false;
+
+ /* we have to remember the encoder header, i.e. the first
+ bytes of encoder output after opening it, because it has to
+ be sent to every new client */
+ header = ReadPage();
+
+ unflushed_input = 0;
+
+ return true;
+}
+
+inline bool
+HttpdOutput::Open(AudioFormat &audio_format, GError **error_r)
+{
+ assert(!open);
+ assert(clients.empty());
+
+ /* open the encoder */
+
+ if (!OpenEncoder(audio_format, error_r))
+ return false;
+
+ /* initialize other attributes */
+
+ clients_cnt = 0;
+ timer = new Timer(audio_format);
+
+ open = true;
+
+ return true;
+}
+
+static bool
+httpd_output_open(struct audio_output *ao, AudioFormat &audio_format,
+ GError **error)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ assert(httpd->clients.empty());
+
+ const ScopeLock protect(httpd->mutex);
+ return httpd->Open(audio_format, error);
+}
+
+inline void
+HttpdOutput::Close()
+{
+ assert(open);
+
+ open = false;
+
+ delete timer;
+
+ clients.clear();
+
+ if (header != NULL)
+ header->Unref();
+
+ encoder_close(encoder);
+}
+
+static void
+httpd_output_close(struct audio_output *ao)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ const ScopeLock protect(httpd->mutex);
+ httpd->Close();
+}
+
+void
+HttpdOutput::RemoveClient(HttpdClient &client)
+{
+ assert(clients_cnt > 0);
+
+ for (auto prev = clients.before_begin(), i = std::next(prev);;
+ prev = i, i = std::next(prev)) {
+ assert(i != clients.end());
+ if (&*i == &client) {
+ clients.erase_after(prev);
+ clients_cnt--;
+ break;
+ }
+ }
+}
+
+void
+HttpdOutput::SendHeader(HttpdClient &client) const
+{
+ if (header != NULL)
+ client.PushPage(header);
+}
+
+static unsigned
+httpd_output_delay(struct audio_output *ao)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ if (!httpd->LockHasClients() && httpd->base.pause) {
+ /* if there's no client and this output is paused,
+ then httpd_output_pause() will not do anything, it
+ will not fill the buffer and it will not update the
+ timer; therefore, we reset the timer here */
+ httpd->timer->Reset();
+
+ /* some arbitrary delay that is long enough to avoid
+ consuming too much CPU, and short enough to notice
+ new clients quickly enough */
+ return 1000;
+ }
+
+ return httpd->timer->IsStarted()
+ ? httpd->timer->GetDelay()
+ : 0;
+}
+
+void
+HttpdOutput::BroadcastPage(Page *page)
+{
+ assert(page != NULL);
+
+ const ScopeLock protect(mutex);
+ for (auto &client : clients)
+ client.PushPage(page);
+}
+
+void
+HttpdOutput::BroadcastFromEncoder()
+{
+ mutex.lock();
+ for (auto &client : clients) {
+ if (client.GetQueueSize() > 256 * 1024) {
+ g_debug("client is too slow, flushing its queue");
+ client.CancelQueue();
+ }
+ }
+ mutex.unlock();
+
+ Page *page;
+ while ((page = ReadPage()) != nullptr) {
+ BroadcastPage(page);
+ page->Unref();
+ }
+}
+
+inline bool
+HttpdOutput::EncodeAndPlay(const void *chunk, size_t size, GError **error_r)
+{
+ if (!encoder_write(encoder, chunk, size, error_r))
+ return false;
+
+ unflushed_input += size;
+
+ BroadcastFromEncoder();
+ return true;
+}
+
+static size_t
+httpd_output_play(struct audio_output *ao, const void *chunk, size_t size,
+ GError **error_r)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ if (httpd->LockHasClients()) {
+ if (!httpd->EncodeAndPlay(chunk, size, error_r))
+ return 0;
+ }
+
+ if (!httpd->timer->IsStarted())
+ httpd->timer->Start();
+ httpd->timer->Add(size);
+
+ return size;
+}
+
+static bool
+httpd_output_pause(struct audio_output *ao)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ if (httpd->LockHasClients()) {
+ static const char silence[1020] = { 0 };
+ return httpd_output_play(ao, silence, sizeof(silence),
+ NULL) > 0;
+ } else {
+ return true;
+ }
+}
+
+inline void
+HttpdOutput::SendTag(const Tag *tag)
+{
+ assert(tag != NULL);
+
+ if (encoder->plugin.tag != nullptr) {
+ /* embed encoder tags */
+
+ /* flush the current stream, and end it */
+
+ encoder_pre_tag(encoder, NULL);
+ BroadcastFromEncoder();
+
+ /* send the tag to the encoder - which starts a new
+ stream now */
+
+ encoder_tag(encoder, tag, NULL);
+
+ /* the first page generated by the encoder will now be
+ used as the new "header" page, which is sent to all
+ new clients */
+
+ Page *page = ReadPage();
+ if (page != NULL) {
+ if (header != NULL)
+ header->Unref();
+ header = page;
+ BroadcastPage(page);
+ }
+ } else {
+ /* use Icy-Metadata */
+
+ if (metadata != NULL)
+ metadata->Unref();
+
+ static constexpr tag_type types[] = {
+ TAG_ALBUM, TAG_ARTIST, TAG_TITLE,
+ TAG_NUM_OF_ITEM_TYPES
+ };
+
+ metadata = icy_server_metadata_page(*tag, &types[0]);
+ if (metadata != NULL) {
+ const ScopeLock protect(mutex);
+ for (auto &client : clients)
+ client.PushMetaData(metadata);
+ }
+ }
+}
+
+static void
+httpd_output_tag(struct audio_output *ao, const Tag *tag)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ httpd->SendTag(tag);
+}
+
+static void
+httpd_output_cancel(struct audio_output *ao)
+{
+ HttpdOutput *httpd = Cast(ao);
+
+ const ScopeLock protect(httpd->mutex);
+ for (auto &client : httpd->clients)
+ client.CancelQueue();
+}
+
+const struct audio_output_plugin httpd_output_plugin = {
+ "httpd",
+ nullptr,
+ httpd_output_init,
+ httpd_output_finish,
+ httpd_output_enable,
+ httpd_output_disable,
+ httpd_output_open,
+ httpd_output_close,
+ httpd_output_delay,
+ httpd_output_tag,
+ httpd_output_play,
+ nullptr,
+ httpd_output_cancel,
+ httpd_output_pause,
+ nullptr,
+};
diff --git a/src/output/httpd_output_plugin.h b/src/output/HttpdOutputPlugin.hxx
index d0eb1533f..c74d2bd4a 100644
--- a/src/output/httpd_output_plugin.h
+++ b/src/output/HttpdOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_HTTPD_OUTPUT_PLUGIN_H
-#define MPD_HTTPD_OUTPUT_PLUGIN_H
+#ifndef MPD_HTTPD_OUTPUT_PLUGIN_HXX
+#define MPD_HTTPD_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin httpd_output_plugin;
diff --git a/src/output/jack_output_plugin.c b/src/output/JackOutputPlugin.cxx
index d5c8ca412..241857d82 100644
--- a/src/output/jack_output_plugin.c
+++ b/src/output/JackOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,8 @@
*/
#include "config.h"
-#include "jack_output_plugin.h"
-#include "output_api.h"
+#include "JackOutputPlugin.hxx"
+#include "OutputAPI.hxx"
#include <assert.h>
@@ -29,6 +29,7 @@
#include <jack/ringbuffer.h>
#include <stdlib.h>
+#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
@@ -43,7 +44,7 @@ enum {
static const size_t jack_sample_size = sizeof(jack_default_audio_sample_t);
-struct jack_data {
+struct JackOutput {
struct audio_output base;
/**
@@ -66,7 +67,7 @@ struct jack_data {
size_t ringbuffer_size;
/* the current audio format */
- struct audio_format audio_format;
+ AudioFormat audio_format;
/* jack library stuff */
jack_port_t *ports[MAX_PORTS];
@@ -80,6 +81,15 @@ struct jack_data {
* silence.
*/
bool pause;
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &jack_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
};
/**
@@ -96,7 +106,7 @@ jack_output_quark(void)
* channels.
*/
static jack_nframes_t
-mpd_jack_available(const struct jack_data *jd)
+mpd_jack_available(const JackOutput *jd)
{
size_t min = jack_ringbuffer_read_space(jd->ringbuffer[0]);
@@ -114,8 +124,7 @@ mpd_jack_available(const struct jack_data *jd)
static int
mpd_jack_process(jack_nframes_t nframes, void *arg)
{
- struct jack_data *jd = (struct jack_data *) arg;
- jack_default_audio_sample_t *out;
+ JackOutput *jd = (JackOutput *) arg;
if (nframes <= 0)
return 0;
@@ -131,7 +140,9 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
/* generate silence while MPD is paused */
for (unsigned i = 0; i < jd->audio_format.channels; ++i) {
- out = jack_port_get_buffer(jd->ports[i], nframes);
+ jack_default_audio_sample_t *out =
+ (jack_default_audio_sample_t *)
+ jack_port_get_buffer(jd->ports[i], nframes);
for (jack_nframes_t f = 0; f < nframes; ++f)
out[f] = 0.0;
@@ -145,8 +156,10 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
available = nframes;
for (unsigned i = 0; i < jd->audio_format.channels; ++i) {
- out = jack_port_get_buffer(jd->ports[i], nframes);
- if (out == NULL)
+ jack_default_audio_sample_t *out =
+ (jack_default_audio_sample_t *)
+ jack_port_get_buffer(jd->ports[i], nframes);
+ if (out == nullptr)
/* workaround for libjack1 bug: if the server
connection fails, the process callback is
invoked anyway, but unable to get a
@@ -165,8 +178,10 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
for (unsigned i = jd->audio_format.channels;
i < jd->num_source_ports; ++i) {
- out = jack_port_get_buffer(jd->ports[i], nframes);
- if (out == NULL)
+ jack_default_audio_sample_t *out =
+ (jack_default_audio_sample_t *)
+ jack_port_get_buffer(jd->ports[i], nframes);
+ if (out == nullptr)
/* workaround for libjack1 bug: if the server
connection fails, the process callback is
invoked anyway, but unable to get a
@@ -183,23 +198,23 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
static void
mpd_jack_shutdown(void *arg)
{
- struct jack_data *jd = (struct jack_data *) arg;
+ JackOutput *jd = (JackOutput *) arg;
jd->shutdown = true;
}
static void
-set_audioformat(struct jack_data *jd, struct audio_format *audio_format)
+set_audioformat(JackOutput *jd, AudioFormat &audio_format)
{
- audio_format->sample_rate = jack_get_sample_rate(jd->client);
+ audio_format.sample_rate = jack_get_sample_rate(jd->client);
if (jd->num_source_ports == 1)
- audio_format->channels = 1;
- else if (audio_format->channels > jd->num_source_ports)
- audio_format->channels = 2;
+ audio_format.channels = 1;
+ else if (audio_format.channels > jd->num_source_ports)
+ audio_format.channels = 2;
- if (audio_format->format != SAMPLE_FORMAT_S16 &&
- audio_format->format != SAMPLE_FORMAT_S24_P32)
- audio_format->format = SAMPLE_FORMAT_S24_P32;
+ if (audio_format.format != SampleFormat::S16 &&
+ audio_format.format != SampleFormat::S24_P32)
+ audio_format.format = SampleFormat::S24_P32;
}
static void
@@ -220,14 +235,14 @@ mpd_jack_info(const char *msg)
* Disconnect the JACK client.
*/
static void
-mpd_jack_disconnect(struct jack_data *jd)
+mpd_jack_disconnect(JackOutput *jd)
{
- assert(jd != NULL);
- assert(jd->client != NULL);
+ assert(jd != nullptr);
+ assert(jd->client != nullptr);
jack_deactivate(jd->client);
jack_client_close(jd->client);
- jd->client = NULL;
+ jd->client = nullptr;
}
/**
@@ -235,17 +250,17 @@ mpd_jack_disconnect(struct jack_data *jd)
* (e.g. register callbacks).
*/
static bool
-mpd_jack_connect(struct jack_data *jd, GError **error_r)
+mpd_jack_connect(JackOutput *jd, GError **error_r)
{
jack_status_t status;
- assert(jd != NULL);
+ assert(jd != nullptr);
jd->shutdown = false;
jd->client = jack_client_open(jd->name, jd->options, &status,
jd->server_name);
- if (jd->client == NULL) {
+ if (jd->client == nullptr) {
g_set_error(error_r, jack_output_quark(), 0,
"Failed to connect to JACK server, status=%d",
status);
@@ -260,7 +275,7 @@ mpd_jack_connect(struct jack_data *jd, GError **error_r)
jd->source_ports[i],
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
- if (jd->ports[i] == NULL) {
+ if (jd->ports[i] == nullptr) {
g_set_error(error_r, jack_output_quark(), 0,
"Cannot register output port \"%s\"",
jd->source_ports[i]);
@@ -284,7 +299,7 @@ parse_port_list(int line, const char *source, char **dest, GError **error_r)
char **list = g_strsplit(source, ",", 0);
unsigned n = 0;
- for (n = 0; list[n] != NULL; ++n) {
+ 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",
@@ -308,59 +323,59 @@ parse_port_list(int line, const char *source, char **dest, GError **error_r)
}
static struct audio_output *
-mpd_jack_init(const struct config_param *param, GError **error_r)
+mpd_jack_init(const config_param &param, GError **error_r)
{
- struct jack_data *jd = g_new(struct jack_data, 1);
+ JackOutput *jd = new JackOutput();
- if (!ao_base_init(&jd->base, &jack_output_plugin, param, error_r)) {
- g_free(jd);
- return NULL;
+ if (!jd->Initialize(param, error_r)) {
+ delete jd;
+ return nullptr;
}
const char *value;
jd->options = JackNullOption;
- jd->name = config_get_block_string(param, "client_name", NULL);
- if (jd->name != NULL)
- jd->options |= JackUseExactName;
+ jd->name = param.GetBlockValue("client_name", nullptr);
+ if (jd->name != nullptr)
+ jd->options = jack_options_t(jd->options | JackUseExactName);
else
/* if there's a no configured client name, we don't
care about the JackUseExactName option */
jd->name = "Music Player Daemon";
- jd->server_name = config_get_block_string(param, "server_name", NULL);
- if (jd->server_name != NULL)
- jd->options |= JackServerName;
+ jd->server_name = param.GetBlockValue("server_name", nullptr);
+ if (jd->server_name != nullptr)
+ jd->options = jack_options_t(jd->options | JackServerName);
- if (!config_get_block_bool(param, "autostart", false))
- jd->options |= JackNoStartServer;
+ if (!param.GetBlockValue("autostart", false))
+ jd->options = jack_options_t(jd->options | JackNoStartServer);
/* configure the source ports */
- value = config_get_block_string(param, "source_ports", "left,right");
- jd->num_source_ports = parse_port_list(param->line, value,
+ value = param.GetBlockValue("source_ports", "left,right");
+ jd->num_source_ports = parse_port_list(param.line, value,
jd->source_ports, error_r);
if (jd->num_source_ports == 0)
- return NULL;
+ return nullptr;
/* configure the destination ports */
- value = config_get_block_string(param, "destination_ports", NULL);
- if (value == NULL) {
+ value = param.GetBlockValue("destination_ports", nullptr);
+ if (value == nullptr) {
/* compatibility with MPD < 0.16 */
- value = config_get_block_string(param, "ports", NULL);
- if (value != NULL)
+ value = param.GetBlockValue("ports", nullptr);
+ if (value != nullptr)
g_warning("deprecated option 'ports' in line %d",
- param->line);
+ param.line);
}
- if (value != NULL) {
+ if (value != nullptr) {
jd->num_destination_ports =
- parse_port_list(param->line, value,
+ parse_port_list(param.line, value,
jd->destination_ports, error_r);
if (jd->num_destination_ports == 0)
- return NULL;
+ return nullptr;
} else {
jd->num_destination_ports = 0;
}
@@ -370,10 +385,9 @@ mpd_jack_init(const struct config_param *param, GError **error_r)
g_warning("number of source ports (%u) mismatches the "
"number of destination ports (%u) in line %d",
jd->num_source_ports, jd->num_destination_ports,
- param->line);
+ param.line);
- jd->ringbuffer_size =
- config_get_block_unsigned(param, "ringbuffer_size", 32768);
+ jd->ringbuffer_size = param.GetBlockValue("ringbuffer_size", 32768u);
jack_set_error_function(mpd_jack_error);
@@ -387,7 +401,7 @@ mpd_jack_init(const struct config_param *param, GError **error_r)
static void
mpd_jack_finish(struct audio_output *ao)
{
- struct jack_data *jd = (struct jack_data *)ao;
+ JackOutput *jd = (JackOutput *)ao;
for (unsigned i = 0; i < jd->num_source_ports; ++i)
g_free(jd->source_ports[i]);
@@ -395,17 +409,17 @@ mpd_jack_finish(struct audio_output *ao)
for (unsigned i = 0; i < jd->num_destination_ports; ++i)
g_free(jd->destination_ports[i]);
- ao_base_finish(&jd->base);
- g_free(jd);
+ jd->Deinitialize();
+ delete jd;
}
static bool
mpd_jack_enable(struct audio_output *ao, GError **error_r)
{
- struct jack_data *jd = (struct jack_data *)ao;
+ JackOutput *jd = (JackOutput *)ao;
for (unsigned i = 0; i < jd->num_source_ports; ++i)
- jd->ringbuffer[i] = NULL;
+ jd->ringbuffer[i] = nullptr;
return mpd_jack_connect(jd, error_r);
}
@@ -413,15 +427,15 @@ mpd_jack_enable(struct audio_output *ao, GError **error_r)
static void
mpd_jack_disable(struct audio_output *ao)
{
- struct jack_data *jd = (struct jack_data *)ao;
+ JackOutput *jd = (JackOutput *)ao;
- if (jd->client != NULL)
+ if (jd->client != nullptr)
mpd_jack_disconnect(jd);
for (unsigned i = 0; i < jd->num_source_ports; ++i) {
- if (jd->ringbuffer[i] != NULL) {
+ if (jd->ringbuffer[i] != nullptr) {
jack_ringbuffer_free(jd->ringbuffer[i]);
- jd->ringbuffer[i] = NULL;
+ jd->ringbuffer[i] = nullptr;
}
}
}
@@ -430,11 +444,11 @@ mpd_jack_disable(struct audio_output *ao)
* Stops the playback on the JACK connection.
*/
static void
-mpd_jack_stop(struct jack_data *jd)
+mpd_jack_stop(JackOutput *jd)
{
- assert(jd != NULL);
+ assert(jd != nullptr);
- if (jd->client == NULL)
+ if (jd->client == nullptr)
return;
if (jd->shutdown)
@@ -446,13 +460,13 @@ mpd_jack_stop(struct jack_data *jd)
}
static bool
-mpd_jack_start(struct jack_data *jd, GError **error_r)
+mpd_jack_start(JackOutput *jd, GError **error_r)
{
const char *destination_ports[MAX_PORTS], **jports;
- const char *duplicate_port = NULL;
+ const char *duplicate_port = nullptr;
unsigned num_destination_ports;
- assert(jd->client != NULL);
+ assert(jd->client != nullptr);
assert(jd->audio_format.channels <= jd->num_source_ports);
/* allocate the ring buffers on the first open(); these
@@ -460,7 +474,7 @@ mpd_jack_start(struct jack_data *jd, GError **error_r)
because we can never know when mpd_jack_process() gets
called */
for (unsigned i = 0; i < jd->num_source_ports; ++i) {
- if (jd->ringbuffer[i] == NULL)
+ if (jd->ringbuffer[i] == nullptr)
jd->ringbuffer[i] =
jack_ringbuffer_create(jd->ringbuffer_size);
@@ -479,20 +493,20 @@ mpd_jack_start(struct jack_data *jd, GError **error_r)
if (jd->num_destination_ports == 0) {
/* no output ports were configured - ask libjack for
defaults */
- jports = jack_get_ports(jd->client, NULL, NULL,
+ jports = jack_get_ports(jd->client, nullptr, nullptr,
JackPortIsPhysical | JackPortIsInput);
- if (jports == NULL) {
+ if (jports == nullptr) {
g_set_error(error_r, jack_output_quark(), 0,
"no ports found");
mpd_jack_stop(jd);
return false;
}
- assert(*jports != NULL);
+ assert(*jports != nullptr);
for (num_destination_ports = 0;
num_destination_ports < MAX_PORTS &&
- jports[num_destination_ports] != NULL;
+ jports[num_destination_ports] != nullptr;
++num_destination_ports) {
g_debug("destination_port[%u] = '%s'\n",
num_destination_ports,
@@ -507,7 +521,7 @@ mpd_jack_start(struct jack_data *jd, GError **error_r)
memcpy(destination_ports, jd->destination_ports,
num_destination_ports * sizeof(*destination_ports));
- jports = NULL;
+ jports = nullptr;
}
assert(num_destination_ports > 0);
@@ -541,7 +555,7 @@ mpd_jack_start(struct jack_data *jd, GError **error_r)
"Not a valid JACK port: %s",
destination_ports[i]);
- if (jports != NULL)
+ if (jports != nullptr)
free(jports);
mpd_jack_stop(jd);
@@ -549,7 +563,7 @@ mpd_jack_start(struct jack_data *jd, GError **error_r)
}
}
- if (duplicate_port != NULL) {
+ if (duplicate_port != nullptr) {
/* mono input file: connect the one source channel to
the both destination channels */
int ret;
@@ -561,7 +575,7 @@ mpd_jack_start(struct jack_data *jd, GError **error_r)
"Not a valid JACK port: %s",
duplicate_port);
- if (jports != NULL)
+ if (jports != nullptr)
free(jports);
mpd_jack_stop(jd);
@@ -569,30 +583,30 @@ mpd_jack_start(struct jack_data *jd, GError **error_r)
}
}
- if (jports != NULL)
+ if (jports != nullptr)
free(jports);
return true;
}
static bool
-mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format,
+mpd_jack_open(struct audio_output *ao, AudioFormat &audio_format,
GError **error_r)
{
- struct jack_data *jd = (struct jack_data *)ao;
+ JackOutput *jd = (JackOutput *)ao;
- assert(jd != NULL);
+ assert(jd != nullptr);
jd->pause = false;
- if (jd->client != NULL && jd->shutdown)
+ if (jd->client != nullptr && jd->shutdown)
mpd_jack_disconnect(jd);
- if (jd->client == NULL && !mpd_jack_connect(jd, error_r))
+ if (jd->client == nullptr && !mpd_jack_connect(jd, error_r))
return false;
set_audioformat(jd, audio_format);
- jd->audio_format = *audio_format;
+ jd->audio_format = audio_format;
if (!mpd_jack_start(jd, error_r))
return false;
@@ -603,7 +617,7 @@ mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format,
static void
mpd_jack_close(G_GNUC_UNUSED struct audio_output *ao)
{
- struct jack_data *jd = (struct jack_data *)ao;
+ JackOutput *jd = (JackOutput *)ao;
mpd_jack_stop(jd);
}
@@ -611,7 +625,7 @@ mpd_jack_close(G_GNUC_UNUSED struct audio_output *ao)
static unsigned
mpd_jack_delay(struct audio_output *ao)
{
- struct jack_data *jd = (struct jack_data *)ao;
+ JackOutput *jd = (JackOutput *)ao;
return jd->base.pause && jd->pause && !jd->shutdown
? 1000
@@ -625,7 +639,7 @@ sample_16_to_jack(int16_t sample)
}
static void
-mpd_jack_write_samples_16(struct jack_data *jd, const int16_t *src,
+mpd_jack_write_samples_16(JackOutput *jd, const int16_t *src,
unsigned num_samples)
{
jack_default_audio_sample_t sample;
@@ -634,7 +648,8 @@ mpd_jack_write_samples_16(struct jack_data *jd, const int16_t *src,
while (num_samples-- > 0) {
for (i = 0; i < jd->audio_format.channels; ++i) {
sample = sample_16_to_jack(*src++);
- jack_ringbuffer_write(jd->ringbuffer[i], (void*)&sample,
+ jack_ringbuffer_write(jd->ringbuffer[i],
+ (const char *)&sample,
sizeof(sample));
}
}
@@ -647,7 +662,7 @@ sample_24_to_jack(int32_t sample)
}
static void
-mpd_jack_write_samples_24(struct jack_data *jd, const int32_t *src,
+mpd_jack_write_samples_24(JackOutput *jd, const int32_t *src,
unsigned num_samples)
{
jack_default_audio_sample_t sample;
@@ -656,29 +671,31 @@ mpd_jack_write_samples_24(struct jack_data *jd, const int32_t *src,
while (num_samples-- > 0) {
for (i = 0; i < jd->audio_format.channels; ++i) {
sample = sample_24_to_jack(*src++);
- jack_ringbuffer_write(jd->ringbuffer[i], (void*)&sample,
+ jack_ringbuffer_write(jd->ringbuffer[i],
+ (const char *)&sample,
sizeof(sample));
}
}
}
static void
-mpd_jack_write_samples(struct jack_data *jd, const void *src,
+mpd_jack_write_samples(JackOutput *jd, const void *src,
unsigned num_samples)
{
switch (jd->audio_format.format) {
- case SAMPLE_FORMAT_S16:
+ case SampleFormat::S16:
mpd_jack_write_samples_16(jd, (const int16_t*)src,
num_samples);
break;
- case SAMPLE_FORMAT_S24_P32:
+ case SampleFormat::S24_P32:
mpd_jack_write_samples_24(jd, (const int32_t*)src,
num_samples);
break;
default:
assert(false);
+ gcc_unreachable();
}
}
@@ -686,8 +703,8 @@ static size_t
mpd_jack_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error_r)
{
- struct jack_data *jd = (struct jack_data *)ao;
- const size_t frame_size = audio_format_frame_size(&jd->audio_format);
+ JackOutput *jd = (JackOutput *)ao;
+ const size_t frame_size = jd->audio_format.GetFrameSize();
size_t space = 0, space1;
jd->pause = false;
@@ -730,7 +747,7 @@ mpd_jack_play(struct audio_output *ao, const void *chunk, size_t size,
static bool
mpd_jack_pause(struct audio_output *ao)
{
- struct jack_data *jd = (struct jack_data *)ao;
+ JackOutput *jd = (JackOutput *)ao;
if (jd->shutdown)
return false;
@@ -741,15 +758,19 @@ mpd_jack_pause(struct audio_output *ao)
}
const struct audio_output_plugin jack_output_plugin = {
- .name = "jack",
- .test_default_device = mpd_jack_test_default_device,
- .init = mpd_jack_init,
- .finish = mpd_jack_finish,
- .enable = mpd_jack_enable,
- .disable = mpd_jack_disable,
- .open = mpd_jack_open,
- .delay = mpd_jack_delay,
- .play = mpd_jack_play,
- .pause = mpd_jack_pause,
- .close = mpd_jack_close,
+ "jack",
+ mpd_jack_test_default_device,
+ mpd_jack_init,
+ mpd_jack_finish,
+ mpd_jack_enable,
+ mpd_jack_disable,
+ mpd_jack_open,
+ mpd_jack_close,
+ mpd_jack_delay,
+ nullptr,
+ mpd_jack_play,
+ nullptr,
+ nullptr,
+ mpd_jack_pause,
+ nullptr,
};
diff --git a/src/output/jack_output_plugin.h b/src/output/JackOutputPlugin.hxx
index 2f94ae7dc..908105ad2 100644
--- a/src/output/jack_output_plugin.h
+++ b/src/output/JackOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_JACK_OUTPUT_PLUGIN_H
-#define MPD_JACK_OUTPUT_PLUGIN_H
+#ifndef MPD_JACK_OUTPUT_PLUGIN_HXX
+#define MPD_JACK_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin jack_output_plugin;
diff --git a/src/output/NullOutputPlugin.cxx b/src/output/NullOutputPlugin.cxx
new file mode 100644
index 000000000..0ce32fbda
--- /dev/null
+++ b/src/output/NullOutputPlugin.cxx
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "NullOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "Timer.hxx"
+
+#include <assert.h>
+
+struct NullOutput {
+ struct audio_output base;
+
+ bool sync;
+
+ Timer *timer;
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &null_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
+};
+
+static struct audio_output *
+null_init(const config_param &param, GError **error_r)
+{
+ NullOutput *nd = new NullOutput();
+
+ if (!nd->Initialize(param, error_r)) {
+ delete nd;
+ return nullptr;
+ }
+
+ nd->sync = param.GetBlockValue("sync", true);
+
+ return &nd->base;
+}
+
+static void
+null_finish(struct audio_output *ao)
+{
+ NullOutput *nd = (NullOutput *)ao;
+
+ nd->Deinitialize();
+ delete nd;
+}
+
+static bool
+null_open(struct audio_output *ao, AudioFormat &audio_format,
+ gcc_unused GError **error)
+{
+ NullOutput *nd = (NullOutput *)ao;
+
+ if (nd->sync)
+ nd->timer = new Timer(audio_format);
+
+ return true;
+}
+
+static void
+null_close(struct audio_output *ao)
+{
+ NullOutput *nd = (NullOutput *)ao;
+
+ if (nd->sync)
+ delete nd->timer;
+}
+
+static unsigned
+null_delay(struct audio_output *ao)
+{
+ NullOutput *nd = (NullOutput *)ao;
+
+ return nd->sync && nd->timer->IsStarted()
+ ? nd->timer->GetDelay()
+ : 0;
+}
+
+static size_t
+null_play(struct audio_output *ao, gcc_unused const void *chunk, size_t size,
+ gcc_unused GError **error)
+{
+ NullOutput *nd = (NullOutput *)ao;
+ Timer *timer = nd->timer;
+
+ if (!nd->sync)
+ return size;
+
+ if (!timer->IsStarted())
+ timer->Start();
+ timer->Add(size);
+
+ return size;
+}
+
+static void
+null_cancel(struct audio_output *ao)
+{
+ NullOutput *nd = (NullOutput *)ao;
+
+ if (!nd->sync)
+ return;
+
+ nd->timer->Reset();
+}
+
+const struct audio_output_plugin null_output_plugin = {
+ "null",
+ nullptr,
+ null_init,
+ null_finish,
+ nullptr,
+ nullptr,
+ null_open,
+ null_close,
+ null_delay,
+ nullptr,
+ null_play,
+ nullptr,
+ null_cancel,
+ nullptr,
+ nullptr,
+};
diff --git a/src/output/null_output_plugin.h b/src/output/NullOutputPlugin.hxx
index 392bf0aa3..a58f1cb13 100644
--- a/src/output/null_output_plugin.h
+++ b/src/output/NullOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_NULL_OUTPUT_PLUGIN_H
-#define MPD_NULL_OUTPUT_PLUGIN_H
+#ifndef MPD_NULL_OUTPUT_PLUGIN_HXX
+#define MPD_NULL_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin null_output_plugin;
diff --git a/src/output/osx_output_plugin.c b/src/output/OSXOutputPlugin.cxx
index cd51fca20..6e42b2518 100644
--- a/src/output/osx_output_plugin.c
+++ b/src/output/OSXOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2012 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,9 +18,11 @@
*/
#include "config.h"
-#include "osx_output_plugin.h"
-#include "output_api.h"
-#include "fifo_buffer.h"
+#include "OSXOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "util/fifo_buffer.h"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
#include <glib.h>
#include <CoreAudio/AudioHardware.h>
@@ -30,7 +32,7 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "osx"
-struct osx_output {
+struct OSXOutput {
struct audio_output base;
/* configuration settings */
@@ -39,8 +41,8 @@ struct osx_output {
const char *device_name;
AudioUnit au;
- GMutex *mutex;
- GCond *condition;
+ Mutex mutex;
+ Cond condition;
struct fifo_buffer *buffer;
};
@@ -63,9 +65,9 @@ osx_output_test_default_device(void)
}
static void
-osx_output_configure(struct osx_output *oo, const struct config_param *param)
+osx_output_configure(OSXOutput *oo, const config_param &param)
{
- const char *device = config_get_block_string(param, "device", NULL);
+ const char *device = param.GetBlockValue("device");
if (device == NULL || 0 == strcmp(device, "default")) {
oo->component_subtype = kAudioUnitSubType_DefaultOutput;
@@ -83,17 +85,15 @@ osx_output_configure(struct osx_output *oo, const struct config_param *param)
}
static struct audio_output *
-osx_output_init(const struct config_param *param, GError **error_r)
+osx_output_init(const config_param &param, GError **error_r)
{
- struct osx_output *oo = g_new(struct osx_output, 1);
+ OSXOutput *oo = new OSXOutput();
if (!ao_base_init(&oo->base, &osx_output_plugin, param, error_r)) {
- g_free(oo);
+ delete oo;
return NULL;
}
osx_output_configure(oo, param);
- oo->mutex = g_mutex_new();
- oo->condition = g_cond_new();
return &oo->base;
}
@@ -101,15 +101,13 @@ osx_output_init(const struct config_param *param, GError **error_r)
static void
osx_output_finish(struct audio_output *ao)
{
- struct osx_output *od = (struct osx_output *)ao;
+ OSXOutput *oo = (OSXOutput *)ao;
- g_mutex_free(od->mutex);
- g_cond_free(od->condition);
- g_free(od);
+ delete oo;
}
static bool
-osx_output_set_device(struct osx_output *oo, GError **error)
+osx_output_set_device(OSXOutput *oo, GError **error)
{
bool ret = true;
OSStatus status;
@@ -135,7 +133,7 @@ osx_output_set_device(struct osx_output *oo, GError **error)
/* what are the available audio device IDs? */
numdevices = size / sizeof(AudioDeviceID);
- deviceids = g_malloc(size);
+ deviceids = new AudioDeviceID[numdevices];
status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
&size,
deviceids);
@@ -192,8 +190,7 @@ osx_output_set_device(struct osx_output *oo, GError **error)
(unsigned int) deviceids[i], name);
done:
- if (deviceids != NULL)
- g_free(deviceids);
+ delete[] deviceids;
return ret;
}
@@ -205,13 +202,13 @@ osx_render(void *vdata,
G_GNUC_UNUSED UInt32 in_number_frames,
AudioBufferList *buffer_list)
{
- struct osx_output *od = (struct osx_output *) vdata;
+ OSXOutput *od = (OSXOutput *) vdata;
AudioBuffer *buffer = &buffer_list->mBuffers[0];
size_t buffer_size = buffer->mDataByteSize;
assert(od->buffer != NULL);
- g_mutex_lock(od->mutex);
+ od->mutex.lock();
size_t nbytes;
const void *src = fifo_buffer_read(od->buffer, &nbytes);
@@ -225,8 +222,8 @@ osx_render(void *vdata,
} else
nbytes = 0;
- g_cond_signal(od->condition);
- g_mutex_unlock(od->mutex);
+ od->condition.signal();
+ od->mutex.unlock();
buffer->mDataByteSize = nbytes;
@@ -242,7 +239,7 @@ osx_render(void *vdata,
static bool
osx_output_enable(struct audio_output *ao, GError **error_r)
{
- struct osx_output *oo = (struct osx_output *)ao;
+ OSXOutput *oo = (OSXOutput *)ao;
ComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
@@ -293,7 +290,7 @@ osx_output_enable(struct audio_output *ao, GError **error_r)
static void
osx_output_disable(struct audio_output *ao)
{
- struct osx_output *oo = (struct osx_output *)ao;
+ OSXOutput *oo = (OSXOutput *)ao;
CloseComponent(oo->au);
}
@@ -301,17 +298,16 @@ osx_output_disable(struct audio_output *ao)
static void
osx_output_cancel(struct audio_output *ao)
{
- struct osx_output *od = (struct osx_output *)ao;
+ OSXOutput *od = (OSXOutput *)ao;
- g_mutex_lock(od->mutex);
+ const ScopeLock protect(od->mutex);
fifo_buffer_clear(od->buffer);
- g_mutex_unlock(od->mutex);
}
static void
osx_output_close(struct audio_output *ao)
{
- struct osx_output *od = (struct osx_output *)ao;
+ OSXOutput *od = (OSXOutput *)ao;
AudioOutputUnitStop(od->au);
AudioUnitUninitialize(od->au);
@@ -320,30 +316,30 @@ osx_output_close(struct audio_output *ao)
}
static bool
-osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error)
+osx_output_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
{
- struct osx_output *od = (struct osx_output *)ao;
+ OSXOutput *od = (OSXOutput *)ao;
AudioStreamBasicDescription stream_description;
- stream_description.mSampleRate = audio_format->sample_rate;
+ stream_description.mSampleRate = audio_format.sample_rate;
stream_description.mFormatID = kAudioFormatLinearPCM;
stream_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
- switch (audio_format->format) {
- case SAMPLE_FORMAT_S8:
+ switch (audio_format.format) {
+ case SampleFormat::S8:
stream_description.mBitsPerChannel = 8;
break;
- case SAMPLE_FORMAT_S16:
+ case SampleFormat::S16:
stream_description.mBitsPerChannel = 16;
break;
- case SAMPLE_FORMAT_S32:
+ case SampleFormat::S32:
stream_description.mBitsPerChannel = 32;
break;
default:
- audio_format->format = SAMPLE_FORMAT_S32;
+ audio_format.format = SampleFormat::S32;
stream_description.mBitsPerChannel = 32;
break;
}
@@ -352,11 +348,10 @@ osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GErr
stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
#endif
- stream_description.mBytesPerPacket =
- audio_format_frame_size(audio_format);
+ stream_description.mBytesPerPacket = audio_format.GetFrameSize();
stream_description.mFramesPerPacket = 1;
stream_description.mBytesPerFrame = stream_description.mBytesPerPacket;
- stream_description.mChannelsPerFrame = audio_format->channels;
+ stream_description.mChannelsPerFrame = audio_format.channels;
ComponentResult result =
AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
@@ -378,8 +373,8 @@ osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GErr
}
/* create a buffer of 1s */
- od->buffer = fifo_buffer_new(audio_format->sample_rate *
- audio_format_frame_size(audio_format));
+ od->buffer = fifo_buffer_new(audio_format.sample_rate *
+ audio_format.GetFrameSize());
status = AudioOutputUnitStart(od->au);
if (status != 0) {
@@ -397,9 +392,9 @@ static size_t
osx_output_play(struct audio_output *ao, const void *chunk, size_t size,
G_GNUC_UNUSED GError **error)
{
- struct osx_output *od = (struct osx_output *)ao;
+ OSXOutput *od = (OSXOutput *)ao;
- g_mutex_lock(od->mutex);
+ const ScopeLock protect(od->mutex);
void *dest;
size_t max_length;
@@ -410,7 +405,7 @@ osx_output_play(struct audio_output *ao, const void *chunk, size_t size,
break;
/* wait for some free space in the buffer */
- g_cond_wait(od->condition, od->mutex);
+ od->condition.wait(od->mutex);
}
if (size > max_length)
@@ -419,20 +414,23 @@ osx_output_play(struct audio_output *ao, const void *chunk, size_t size,
memcpy(dest, chunk, size);
fifo_buffer_append(od->buffer, size);
- g_mutex_unlock(od->mutex);
-
return size;
}
const struct audio_output_plugin osx_output_plugin = {
- .name = "osx",
- .test_default_device = osx_output_test_default_device,
- .init = osx_output_init,
- .finish = osx_output_finish,
- .enable = osx_output_enable,
- .disable = osx_output_disable,
- .open = osx_output_open,
- .close = osx_output_close,
- .play = osx_output_play,
- .cancel = osx_output_cancel,
+ "osx",
+ osx_output_test_default_device,
+ osx_output_init,
+ osx_output_finish,
+ osx_output_enable,
+ osx_output_disable,
+ osx_output_open,
+ osx_output_close,
+ nullptr,
+ nullptr,
+ osx_output_play,
+ nullptr,
+ osx_output_cancel,
+ nullptr,
+ nullptr,
};
diff --git a/src/output/osx_output_plugin.h b/src/output/OSXOutputPlugin.hxx
index 814702d4f..2a4172880 100644
--- a/src/output/osx_output_plugin.h
+++ b/src/output/OSXOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_OSX_OUTPUT_PLUGIN_H
-#define MPD_OSX_OUTPUT_PLUGIN_H
+#ifndef MPD_OSX_OUTPUT_PLUGIN_HXX
+#define MPD_OSX_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin osx_output_plugin;
diff --git a/src/output/openal_output_plugin.c b/src/output/OpenALOutputPlugin.cxx
index ebd35ef12..1864052fa 100644
--- a/src/output/openal_output_plugin.c
+++ b/src/output/OpenALOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,8 @@
*/
#include "config.h"
-#include "openal_output_plugin.h"
-#include "output_api.h"
+#include "OpenALOutputPlugin.hxx"
+#include "OutputAPI.hxx"
#include <glib.h>
@@ -37,7 +37,7 @@
/* should be enough for buffer size = 2048 */
#define NUM_BUFFERS 16
-struct openal_data {
+struct OpenALOutput {
struct audio_output base;
const char *device_name;
@@ -48,6 +48,15 @@ struct openal_data {
ALuint source;
ALenum format;
ALuint frequency;
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &openal_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
};
static inline GQuark
@@ -57,33 +66,33 @@ openal_output_quark(void)
}
static ALenum
-openal_audio_format(struct audio_format *audio_format)
+openal_audio_format(AudioFormat &audio_format)
{
- /* note: cannot map SAMPLE_FORMAT_S8 to AL_FORMAT_STEREO8 or
+ /* note: cannot map SampleFormat::S8 to AL_FORMAT_STEREO8 or
AL_FORMAT_MONO8 since OpenAL expects unsigned 8 bit
samples, while MPD uses signed samples */
- switch (audio_format->format) {
- case SAMPLE_FORMAT_S16:
- if (audio_format->channels == 2)
+ switch (audio_format.format) {
+ case SampleFormat::S16:
+ if (audio_format.channels == 2)
return AL_FORMAT_STEREO16;
- if (audio_format->channels == 1)
+ if (audio_format.channels == 1)
return AL_FORMAT_MONO16;
/* fall back to mono */
- audio_format->channels = 1;
+ audio_format.channels = 1;
return openal_audio_format(audio_format);
default:
/* fall back to 16 bit */
- audio_format->format = SAMPLE_FORMAT_S16;
+ audio_format.format = SampleFormat::S16;
return openal_audio_format(audio_format);
}
}
G_GNUC_PURE
static inline ALint
-openal_get_source_i(const struct openal_data *od, ALenum param)
+openal_get_source_i(const OpenALOutput *od, ALenum param)
{
ALint value;
alGetSourcei(od->source, param, &value);
@@ -92,34 +101,34 @@ openal_get_source_i(const struct openal_data *od, ALenum param)
G_GNUC_PURE
static inline bool
-openal_has_processed(const struct openal_data *od)
+openal_has_processed(const OpenALOutput *od)
{
return openal_get_source_i(od, AL_BUFFERS_PROCESSED) > 0;
}
G_GNUC_PURE
static inline ALint
-openal_is_playing(const struct openal_data *od)
+openal_is_playing(const OpenALOutput *od)
{
return openal_get_source_i(od, AL_SOURCE_STATE) == AL_PLAYING;
}
static bool
-openal_setup_context(struct openal_data *od,
+openal_setup_context(OpenALOutput *od,
GError **error)
{
od->device = alcOpenDevice(od->device_name);
- if (od->device == NULL) {
+ if (od->device == nullptr) {
g_set_error(error, openal_output_quark(), 0,
"Error opening OpenAL device \"%s\"\n",
od->device_name);
return false;
}
- od->context = alcCreateContext(od->device, NULL);
+ od->context = alcCreateContext(od->device, nullptr);
- if (od->context == NULL) {
+ if (od->context == nullptr) {
g_set_error(error, openal_output_quark(), 0,
"Error creating context for \"%s\"\n",
od->device_name);
@@ -131,19 +140,17 @@ openal_setup_context(struct openal_data *od,
}
static struct audio_output *
-openal_init(const struct config_param *param, GError **error_r)
+openal_init(const config_param &param, GError **error_r)
{
- const char *device_name = config_get_block_string(param, "device", NULL);
- struct openal_data *od;
-
- if (device_name == NULL) {
- device_name = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
+ const char *device_name = param.GetBlockValue("device");
+ if (device_name == nullptr) {
+ device_name = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
}
- od = g_new(struct openal_data, 1);
- if (!ao_base_init(&od->base, &openal_output_plugin, param, error_r)) {
- g_free(od);
- return NULL;
+ OpenALOutput *od = new OpenALOutput();
+ if (!od->Initialize(param, error_r)) {
+ delete od;
+ return nullptr;
}
od->device_name = device_name;
@@ -154,17 +161,17 @@ openal_init(const struct config_param *param, GError **error_r)
static void
openal_finish(struct audio_output *ao)
{
- struct openal_data *od = (struct openal_data *)ao;
+ OpenALOutput *od = (OpenALOutput *)ao;
- ao_base_finish(&od->base);
- g_free(od);
+ od->Deinitialize();
+ delete od;
}
static bool
-openal_open(struct audio_output *ao, struct audio_format *audio_format,
+openal_open(struct audio_output *ao, AudioFormat &audio_format,
GError **error)
{
- struct openal_data *od = (struct openal_data *)ao;
+ OpenALOutput *od = (OpenALOutput *)ao;
od->format = openal_audio_format(audio_format);
@@ -191,7 +198,7 @@ openal_open(struct audio_output *ao, struct audio_format *audio_format,
}
od->filled = 0;
- od->frequency = audio_format->sample_rate;
+ od->frequency = audio_format.sample_rate;
return true;
}
@@ -199,7 +206,7 @@ openal_open(struct audio_output *ao, struct audio_format *audio_format,
static void
openal_close(struct audio_output *ao)
{
- struct openal_data *od = (struct openal_data *)ao;
+ OpenALOutput *od = (OpenALOutput *)ao;
alcMakeContextCurrent(od->context);
alDeleteSources(1, &od->source);
@@ -211,7 +218,7 @@ openal_close(struct audio_output *ao)
static unsigned
openal_delay(struct audio_output *ao)
{
- struct openal_data *od = (struct openal_data *)ao;
+ OpenALOutput *od = (OpenALOutput *)ao;
return od->filled < NUM_BUFFERS || openal_has_processed(od)
? 0
@@ -225,7 +232,7 @@ static size_t
openal_play(struct audio_output *ao, const void *chunk, size_t size,
G_GNUC_UNUSED GError **error)
{
- struct openal_data *od = (struct openal_data *)ao;
+ OpenALOutput *od = (OpenALOutput *)ao;
ALuint buffer;
if (alcGetCurrentContext() != od->context) {
@@ -256,7 +263,7 @@ openal_play(struct audio_output *ao, const void *chunk, size_t size,
static void
openal_cancel(struct audio_output *ao)
{
- struct openal_data *od = (struct openal_data *)ao;
+ OpenALOutput *od = (OpenALOutput *)ao;
od->filled = 0;
alcMakeContextCurrent(od->context);
@@ -268,12 +275,19 @@ openal_cancel(struct audio_output *ao)
}
const struct audio_output_plugin openal_output_plugin = {
- .name = "openal",
- .init = openal_init,
- .finish = openal_finish,
- .open = openal_open,
- .close = openal_close,
- .delay = openal_delay,
- .play = openal_play,
- .cancel = openal_cancel,
+ "openal",
+ nullptr,
+ openal_init,
+ openal_finish,
+ nullptr,
+ nullptr,
+ openal_open,
+ openal_close,
+ openal_delay,
+ nullptr,
+ openal_play,
+ nullptr,
+ openal_cancel,
+ nullptr,
+ nullptr,
};
diff --git a/src/output/openal_output_plugin.h b/src/output/OpenALOutputPlugin.hxx
index 25f6ccf46..e1ebf3d4f 100644
--- a/src/output/openal_output_plugin.h
+++ b/src/output/OpenALOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_OPENAL_OUTPUT_PLUGIN_H
-#define MPD_OPENAL_OUTPUT_PLUGIN_H
+#ifndef MPD_OPENAL_OUTPUT_PLUGIN_HXX
+#define MPD_OPENAL_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin openal_output_plugin;
diff --git a/src/output/oss_output_plugin.c b/src/output/OssOutputPlugin.cxx
index e366a4537..2ef0edd67 100644
--- a/src/output/oss_output_plugin.c
+++ b/src/output/OssOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,11 +18,10 @@
*/
#include "config.h"
-#include "oss_output_plugin.h"
-#include "output_api.h"
-#include "mixer_list.h"
+#include "OssOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "MixerList.hxx"
#include "fd_util.h"
-#include "glib_compat.h"
#include <glib.h>
@@ -53,14 +52,15 @@
#endif
#ifdef AFMT_S24_PACKED
-#include "pcm_export.h"
+#include "pcm/PcmExport.hxx"
+#include "util/Manual.hxx"
#endif
-struct oss_data {
+struct OssOutput {
struct audio_output base;
#ifdef AFMT_S24_PACKED
- struct pcm_export_state export;
+ Manual<PcmExport> pcm_export;
#endif
int fd;
@@ -70,13 +70,24 @@ struct oss_data {
* The current input audio format. This is needed to reopen
* the device after cancel().
*/
- struct audio_format audio_format;
+ AudioFormat audio_format;
/**
* The current OSS audio format. This is needed to reopen the
* device after cancel().
*/
int oss_format;
+
+ OssOutput():fd(-1), device(nullptr) {}
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &oss_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
};
/**
@@ -88,23 +99,6 @@ oss_output_quark(void)
return g_quark_from_static_string("oss_output");
}
-static struct oss_data *
-oss_data_new(void)
-{
- struct oss_data *ret = g_new(struct oss_data, 1);
-
- ret->device = NULL;
- ret->fd = -1;
-
- return ret;
-}
-
-static void
-oss_data_free(struct oss_data *od)
-{
- g_free(od);
-}
-
enum oss_stat {
OSS_STAT_NO_ERROR = 0,
OSS_STAT_NOT_CHAR_DEV = -1,
@@ -163,17 +157,16 @@ oss_output_test_default_device(void)
static struct audio_output *
oss_open_default(GError **error)
{
- int i;
int err[G_N_ELEMENTS(default_devices)];
enum oss_stat ret[G_N_ELEMENTS(default_devices)];
- for (i = G_N_ELEMENTS(default_devices); --i >= 0; ) {
+ const config_param empty;
+ for (int i = G_N_ELEMENTS(default_devices); --i >= 0; ) {
ret[i] = oss_stat_device(default_devices[i], &err[i]);
if (ret[i] == OSS_STAT_NO_ERROR) {
- struct oss_data *od = oss_data_new();
- if (!ao_base_init(&od->base, &oss_output_plugin, NULL,
- error)) {
- g_free(od);
+ OssOutput *od = new OssOutput();
+ if (!od->Initialize(empty, error)) {
+ delete od;
return NULL;
}
@@ -182,7 +175,7 @@ oss_open_default(GError **error)
}
}
- for (i = G_N_ELEMENTS(default_devices); --i >= 0; ) {
+ for (int i = G_N_ELEMENTS(default_devices); --i >= 0; ) {
const char *dev = default_devices[i];
switch(ret[i]) {
case OSS_STAT_NO_ERROR:
@@ -209,14 +202,13 @@ oss_open_default(GError **error)
}
static struct audio_output *
-oss_output_init(const struct config_param *param, GError **error)
+oss_output_init(const config_param &param, GError **error_r)
{
- const char *device = config_get_block_string(param, "device", NULL);
+ const char *device = param.GetBlockValue("device");
if (device != NULL) {
- struct oss_data *od = oss_data_new();
- if (!ao_base_init(&od->base, &oss_output_plugin, param,
- error)) {
- g_free(od);
+ OssOutput *od = new OssOutput();
+ if (!od->Initialize(param, error_r)) {
+ delete od;
return NULL;
}
@@ -224,16 +216,16 @@ oss_output_init(const struct config_param *param, GError **error)
return &od->base;
}
- return oss_open_default(error);
+ return oss_open_default(error_r);
}
static void
oss_output_finish(struct audio_output *ao)
{
- struct oss_data *od = (struct oss_data *)ao;
+ OssOutput *od = (OssOutput *)ao;
ao_base_finish(&od->base);
- oss_data_free(od);
+ delete od;
}
#ifdef AFMT_S24_PACKED
@@ -241,24 +233,24 @@ oss_output_finish(struct audio_output *ao)
static bool
oss_output_enable(struct audio_output *ao, G_GNUC_UNUSED GError **error_r)
{
- struct oss_data *od = (struct oss_data *)ao;
+ OssOutput *od = (OssOutput *)ao;
- pcm_export_init(&od->export);
+ od->pcm_export.Construct();
return true;
}
static void
oss_output_disable(struct audio_output *ao)
{
- struct oss_data *od = (struct oss_data *)ao;
+ OssOutput *od = (OssOutput *)ao;
- pcm_export_deinit(&od->export);
+ od->pcm_export.Destruct();
}
#endif
static void
-oss_close(struct oss_data *od)
+oss_close(OssOutput *od)
{
if (od->fd >= 0)
close(od->fd);
@@ -317,10 +309,10 @@ oss_try_ioctl(int fd, unsigned long request, int value,
* specified number is not supported.
*/
static bool
-oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
+oss_setup_channels(int fd, AudioFormat &audio_format, GError **error_r)
{
const char *const msg = "Failed to set channel count";
- int channels = audio_format->channels;
+ int channels = audio_format.channels;
enum oss_setup_result result =
oss_try_ioctl_r(fd, SNDCTL_DSP_CHANNELS, &channels, msg, error_r);
switch (result) {
@@ -328,7 +320,7 @@ oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
if (!audio_valid_channel_count(channels))
break;
- audio_format->channels = channels;
+ audio_format.channels = channels;
return true;
case ERROR:
@@ -339,7 +331,7 @@ oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
}
for (unsigned i = 1; i < 2; ++i) {
- if (i == audio_format->channels)
+ if (i == audio_format.channels)
/* don't try that again */
continue;
@@ -351,7 +343,7 @@ oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
if (!audio_valid_channel_count(channels))
break;
- audio_format->channels = channels;
+ audio_format.channels = channels;
return true;
case ERROR:
@@ -371,11 +363,11 @@ oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
* specified sample rate is not supported.
*/
static bool
-oss_setup_sample_rate(int fd, struct audio_format *audio_format,
+oss_setup_sample_rate(int fd, AudioFormat &audio_format,
GError **error_r)
{
const char *const msg = "Failed to set sample rate";
- int sample_rate = audio_format->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);
@@ -384,7 +376,7 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
if (!audio_valid_sample_rate(sample_rate))
break;
- audio_format->sample_rate = sample_rate;
+ audio_format.sample_rate = sample_rate;
return true;
case ERROR:
@@ -397,7 +389,7 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
static const int sample_rates[] = { 48000, 44100, 0 };
for (unsigned i = 0; sample_rates[i] != 0; ++i) {
sample_rate = sample_rates[i];
- if (sample_rate == (int)audio_format->sample_rate)
+ if (sample_rate == (int)audio_format.sample_rate)
continue;
result = oss_try_ioctl_r(fd, SNDCTL_DSP_SPEED, &sample_rate,
@@ -407,7 +399,7 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
if (!audio_valid_sample_rate(sample_rate))
break;
- audio_format->sample_rate = sample_rate;
+ audio_format.sample_rate = sample_rate;
return true;
case ERROR:
@@ -427,28 +419,28 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
* AFMT_QUERY if there is no direct counterpart.
*/
static int
-sample_format_to_oss(enum sample_format format)
+sample_format_to_oss(SampleFormat format)
{
switch (format) {
- case SAMPLE_FORMAT_UNDEFINED:
- case SAMPLE_FORMAT_FLOAT:
- case SAMPLE_FORMAT_DSD:
+ case SampleFormat::UNDEFINED:
+ case SampleFormat::FLOAT:
+ case SampleFormat::DSD:
return AFMT_QUERY;
- case SAMPLE_FORMAT_S8:
+ case SampleFormat::S8:
return AFMT_S8;
- case SAMPLE_FORMAT_S16:
+ case SampleFormat::S16:
return AFMT_S16_NE;
- case SAMPLE_FORMAT_S24_P32:
+ case SampleFormat::S24_P32:
#ifdef AFMT_S24_NE
return AFMT_S24_NE;
#else
return AFMT_QUERY;
#endif
- case SAMPLE_FORMAT_S32:
+ case SampleFormat::S32:
#ifdef AFMT_S32_NE
return AFMT_S32_NE;
#else
@@ -461,50 +453,50 @@ sample_format_to_oss(enum sample_format format)
/**
* Convert an OSS sample format to its MPD counterpart. Returns
- * SAMPLE_FORMAT_UNDEFINED if there is no direct counterpart.
+ * SampleFormat::UNDEFINED if there is no direct counterpart.
*/
-static enum sample_format
+static SampleFormat
sample_format_from_oss(int format)
{
switch (format) {
case AFMT_S8:
- return SAMPLE_FORMAT_S8;
+ return SampleFormat::S8;
case AFMT_S16_NE:
- return SAMPLE_FORMAT_S16;
+ return SampleFormat::S16;
#ifdef AFMT_S24_PACKED
case AFMT_S24_PACKED:
- return SAMPLE_FORMAT_S24_P32;
+ return SampleFormat::S24_P32;
#endif
#ifdef AFMT_S24_NE
case AFMT_S24_NE:
- return SAMPLE_FORMAT_S24_P32;
+ return SampleFormat::S24_P32;
#endif
#ifdef AFMT_S32_NE
case AFMT_S32_NE:
- return SAMPLE_FORMAT_S32;
+ return SampleFormat::S32;
#endif
default:
- return SAMPLE_FORMAT_UNDEFINED;
+ return SampleFormat::UNDEFINED;
}
}
/**
* Probe one sample format.
*
- * @return the selected sample format or SAMPLE_FORMAT_UNDEFINED on
+ * @return the selected sample format or SampleFormat::UNDEFINED on
* error
*/
static enum oss_setup_result
-oss_probe_sample_format(int fd, enum sample_format sample_format,
- enum sample_format *sample_format_r,
+oss_probe_sample_format(int fd, SampleFormat sample_format,
+ SampleFormat *sample_format_r,
int *oss_format_r,
#ifdef AFMT_S24_PACKED
- struct pcm_export_state *export,
+ PcmExport &pcm_export,
#endif
GError **error_r)
{
@@ -518,7 +510,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
"Failed to set sample format", error_r);
#ifdef AFMT_S24_PACKED
- if (result == UNSUPPORTED && sample_format == SAMPLE_FORMAT_S24_P32) {
+ if (result == UNSUPPORTED && sample_format == SampleFormat::S24_P32) {
/* if the driver doesn't support padded 24 bit, try
packed 24 bit */
oss_format = AFMT_S24_PACKED;
@@ -532,14 +524,14 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
return result;
sample_format = sample_format_from_oss(oss_format);
- if (sample_format == SAMPLE_FORMAT_UNDEFINED)
+ if (sample_format == SampleFormat::UNDEFINED)
return UNSUPPORTED;
*sample_format_r = sample_format;
*oss_format_r = oss_format;
#ifdef AFMT_S24_PACKED
- pcm_export_open(export, sample_format, 0, false, false,
+ pcm_export.Open(sample_format, 0, false, false,
oss_format == AFMT_S24_PACKED,
oss_format == AFMT_S24_PACKED &&
G_BYTE_ORDER != G_LITTLE_ENDIAN);
@@ -553,24 +545,24 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
* specified format is not supported.
*/
static bool
-oss_setup_sample_format(int fd, struct audio_format *audio_format,
+oss_setup_sample_format(int fd, AudioFormat &audio_format,
int *oss_format_r,
#ifdef AFMT_S24_PACKED
- struct pcm_export_state *export,
+ PcmExport &pcm_export,
#endif
GError **error_r)
{
- enum sample_format mpd_format;
+ SampleFormat mpd_format;
enum oss_setup_result result =
- oss_probe_sample_format(fd, audio_format->format,
+ oss_probe_sample_format(fd, audio_format.format,
&mpd_format, oss_format_r,
#ifdef AFMT_S24_PACKED
- export,
+ pcm_export,
#endif
error_r);
switch (result) {
case SUCCESS:
- audio_format->format = mpd_format;
+ audio_format.format = mpd_format;
return true;
case ERROR:
@@ -586,29 +578,29 @@ oss_setup_sample_format(int fd, struct audio_format *audio_format,
/* the requested sample format is not available - probe for
other formats supported by MPD */
- static const enum sample_format sample_formats[] = {
- SAMPLE_FORMAT_S24_P32,
- SAMPLE_FORMAT_S32,
- SAMPLE_FORMAT_S16,
- SAMPLE_FORMAT_S8,
- SAMPLE_FORMAT_UNDEFINED /* sentinel */
+ static const SampleFormat sample_formats[] = {
+ SampleFormat::S24_P32,
+ SampleFormat::S32,
+ SampleFormat::S16,
+ SampleFormat::S8,
+ SampleFormat::UNDEFINED /* sentinel */
};
- for (unsigned i = 0; sample_formats[i] != SAMPLE_FORMAT_UNDEFINED; ++i) {
+ for (unsigned i = 0; sample_formats[i] != SampleFormat::UNDEFINED; ++i) {
mpd_format = sample_formats[i];
- if (mpd_format == audio_format->format)
+ if (mpd_format == audio_format.format)
/* don't try that again */
continue;
result = oss_probe_sample_format(fd, mpd_format,
&mpd_format, oss_format_r,
#ifdef AFMT_S24_PACKED
- export,
+ pcm_export,
#endif
error_r);
switch (result) {
case SUCCESS:
- audio_format->format = mpd_format;
+ audio_format.format = mpd_format;
return true;
case ERROR:
@@ -628,14 +620,14 @@ oss_setup_sample_format(int fd, struct audio_format *audio_format,
* Sets up the OSS device which was opened before.
*/
static bool
-oss_setup(struct oss_data *od, struct audio_format *audio_format,
+oss_setup(OssOutput *od, AudioFormat &audio_format,
GError **error_r)
{
return oss_setup_channels(od->fd, audio_format, error_r) &&
oss_setup_sample_rate(od->fd, audio_format, error_r) &&
oss_setup_sample_format(od->fd, audio_format, &od->oss_format,
#ifdef AFMT_S24_PACKED
- &od->export,
+ od->pcm_export,
#endif
error_r);
}
@@ -644,7 +636,7 @@ oss_setup(struct oss_data *od, struct audio_format *audio_format,
* Reopen the device with the saved audio_format, without any probing.
*/
static bool
-oss_reopen(struct oss_data *od, GError **error_r)
+oss_reopen(OssOutput *od, GError **error_r)
{
assert(od->fd < 0);
@@ -696,10 +688,10 @@ oss_reopen(struct oss_data *od, GError **error_r)
}
static bool
-oss_output_open(struct audio_output *ao, struct audio_format *audio_format,
+oss_output_open(struct audio_output *ao, AudioFormat &audio_format,
GError **error)
{
- struct oss_data *od = (struct oss_data *)ao;
+ OssOutput *od = (OssOutput *)ao;
od->fd = open_cloexec(od->device, O_WRONLY, 0);
if (od->fd < 0) {
@@ -714,14 +706,14 @@ oss_output_open(struct audio_output *ao, struct audio_format *audio_format,
return false;
}
- od->audio_format = *audio_format;
+ od->audio_format = audio_format;
return true;
}
static void
oss_output_close(struct audio_output *ao)
{
- struct oss_data *od = (struct oss_data *)ao;
+ OssOutput *od = (OssOutput *)ao;
oss_close(od);
}
@@ -729,7 +721,7 @@ oss_output_close(struct audio_output *ao)
static void
oss_output_cancel(struct audio_output *ao)
{
- struct oss_data *od = (struct oss_data *)ao;
+ OssOutput *od = (OssOutput *)ao;
if (od->fd >= 0) {
ioctl(od->fd, SNDCTL_DSP_RESET, 0);
@@ -741,7 +733,7 @@ static size_t
oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error)
{
- struct oss_data *od = (struct oss_data *)ao;
+ OssOutput *od = (OssOutput *)ao;
ssize_t ret;
/* reopen the device since it was closed by dropBufferedAudio */
@@ -749,14 +741,14 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
return 0;
#ifdef AFMT_S24_PACKED
- chunk = pcm_export(&od->export, chunk, size, &size);
+ chunk = od->pcm_export->Export(chunk, size, size);
#endif
while (true) {
ret = write(od->fd, chunk, size);
if (ret > 0) {
#ifdef AFMT_S24_PACKED
- ret = pcm_export_source_size(&od->export, ret);
+ ret = od->pcm_export->CalcSourceSize(ret);
#endif
return ret;
}
@@ -771,18 +763,25 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
}
const struct audio_output_plugin oss_output_plugin = {
- .name = "oss",
- .test_default_device = oss_output_test_default_device,
- .init = oss_output_init,
- .finish = oss_output_finish,
+ "oss",
+ oss_output_test_default_device,
+ oss_output_init,
+ oss_output_finish,
#ifdef AFMT_S24_PACKED
- .enable = oss_output_enable,
- .disable = oss_output_disable,
+ oss_output_enable,
+ oss_output_disable,
+#else
+ nullptr,
+ nullptr,
#endif
- .open = oss_output_open,
- .close = oss_output_close,
- .play = oss_output_play,
- .cancel = oss_output_cancel,
-
- .mixer_plugin = &oss_mixer_plugin,
+ oss_output_open,
+ oss_output_close,
+ nullptr,
+ nullptr,
+ oss_output_play,
+ nullptr,
+ oss_output_cancel,
+ nullptr,
+
+ &oss_mixer_plugin,
};
diff --git a/src/output/oss_output_plugin.h b/src/output/OssOutputPlugin.hxx
index 2aecc2b3a..6c5c9530b 100644
--- a/src/output/oss_output_plugin.h
+++ b/src/output/OssOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_OSS_OUTPUT_PLUGIN_H
-#define MPD_OSS_OUTPUT_PLUGIN_H
+#ifndef MPD_OSS_OUTPUT_PLUGIN_HXX
+#define MPD_OSS_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin oss_output_plugin;
diff --git a/src/output/pipe_output_plugin.c b/src/output/PipeOutputPlugin.cxx
index 90c5a5331..f485f1554 100644
--- a/src/output/pipe_output_plugin.c
+++ b/src/output/PipeOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,17 +18,28 @@
*/
#include "config.h"
-#include "pipe_output_plugin.h"
-#include "output_api.h"
+#include "PipeOutputPlugin.hxx"
+#include "OutputAPI.hxx"
#include <stdio.h>
#include <errno.h>
-struct pipe_output {
+struct PipeOutput {
struct audio_output base;
char *cmd;
FILE *fh;
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &pipe_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
+
+ bool Configure(const config_param &param, GError **error_r);
};
/**
@@ -40,22 +51,33 @@ pipe_output_quark(void)
return g_quark_from_static_string("pipe_output");
}
+inline bool
+PipeOutput::Configure(const config_param &param, GError **error_r)
+{
+ cmd = param.DupBlockString("command");
+ if (cmd == nullptr) {
+ g_set_error(error_r, pipe_output_quark(), 0,
+ "No \"command\" parameter specified");
+ return false;
+ }
+
+ return true;
+}
+
static struct audio_output *
-pipe_output_init(const struct config_param *param,
- GError **error)
+pipe_output_init(const config_param &param, GError **error_r)
{
- struct pipe_output *pd = g_new(struct pipe_output, 1);
+ PipeOutput *pd = new PipeOutput();
- if (!ao_base_init(&pd->base, &pipe_output_plugin, param, error)) {
- g_free(pd);
- return NULL;
+ if (!pd->Initialize(param, error_r)) {
+ delete pd;
+ return nullptr;
}
- pd->cmd = config_dup_block_string(param, "command", NULL);
- if (pd->cmd == NULL) {
- g_set_error(error, pipe_output_quark(), 0,
- "No \"command\" parameter specified");
- return NULL;
+ if (!pd->Configure(param, error_r)) {
+ pd->Deinitialize();
+ delete pd;
+ return nullptr;
}
return &pd->base;
@@ -64,22 +86,22 @@ pipe_output_init(const struct config_param *param,
static void
pipe_output_finish(struct audio_output *ao)
{
- struct pipe_output *pd = (struct pipe_output *)ao;
+ PipeOutput *pd = (PipeOutput *)ao;
g_free(pd->cmd);
- ao_base_finish(&pd->base);
- g_free(pd);
+ pd->Deinitialize();
+ delete pd;
}
static bool
pipe_output_open(struct audio_output *ao,
- G_GNUC_UNUSED struct audio_format *audio_format,
+ G_GNUC_UNUSED AudioFormat &audio_format,
G_GNUC_UNUSED GError **error)
{
- struct pipe_output *pd = (struct pipe_output *)ao;
+ PipeOutput *pd = (PipeOutput *)ao;
pd->fh = popen(pd->cmd, "w");
- if (pd->fh == NULL) {
+ if (pd->fh == nullptr) {
g_set_error(error, pipe_output_quark(), errno,
"Error opening pipe \"%s\": %s",
pd->cmd, g_strerror(errno));
@@ -92,7 +114,7 @@ pipe_output_open(struct audio_output *ao,
static void
pipe_output_close(struct audio_output *ao)
{
- struct pipe_output *pd = (struct pipe_output *)ao;
+ PipeOutput *pd = (PipeOutput *)ao;
pclose(pd->fh);
}
@@ -100,7 +122,7 @@ 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)
{
- struct pipe_output *pd = (struct pipe_output *)ao;
+ PipeOutput *pd = (PipeOutput *)ao;
size_t ret;
ret = fwrite(chunk, 1, size, pd->fh);
@@ -112,10 +134,19 @@ pipe_output_play(struct audio_output *ao, const void *chunk, size_t size, GError
}
const struct audio_output_plugin pipe_output_plugin = {
- .name = "pipe",
- .init = pipe_output_init,
- .finish = pipe_output_finish,
- .open = pipe_output_open,
- .close = pipe_output_close,
- .play = pipe_output_play,
+ "pipe",
+ nullptr,
+ pipe_output_init,
+ pipe_output_finish,
+ nullptr,
+ nullptr,
+ pipe_output_open,
+ pipe_output_close,
+ nullptr,
+ nullptr,
+ pipe_output_play,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
};
diff --git a/src/output/pipe_output_plugin.h b/src/output/PipeOutputPlugin.hxx
index 9f014f829..f0c29706b 100644
--- a/src/output/pipe_output_plugin.h
+++ b/src/output/PipeOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_PIPE_OUTPUT_PLUGIN_H
-#define MPD_PIPE_OUTPUT_PLUGIN_H
+#ifndef MPD_PIPE_OUTPUT_PLUGIN_HXX
+#define MPD_PIPE_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin pipe_output_plugin;
diff --git a/src/output/pulse_output_plugin.c b/src/output/PulseOutputPlugin.cxx
index e267427df..f59c8d76e 100644
--- a/src/output/pulse_output_plugin.c
+++ b/src/output/PulseOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,10 +18,10 @@
*/
#include "config.h"
-#include "pulse_output_plugin.h"
-#include "output_api.h"
-#include "mixer_list.h"
-#include "mixer/pulse_mixer_plugin.h"
+#include "PulseOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "MixerList.hxx"
+#include "mixer/PulseMixerPlugin.hxx"
#include <glib.h>
@@ -45,14 +45,14 @@
#define PA_CHECK_VERSION(a,b,c) false
#endif
-struct pulse_output {
+struct PulseOutput {
struct audio_output base;
const char *name;
const char *server;
const char *sink;
- struct pulse_mixer *mixer;
+ PulseMixer *mixer;
struct pa_threaded_mainloop *mainloop;
struct pa_context *context;
@@ -79,36 +79,36 @@ pulse_output_quark(void)
}
void
-pulse_output_lock(struct pulse_output *po)
+pulse_output_lock(PulseOutput *po)
{
pa_threaded_mainloop_lock(po->mainloop);
}
void
-pulse_output_unlock(struct pulse_output *po)
+pulse_output_unlock(PulseOutput *po)
{
pa_threaded_mainloop_unlock(po->mainloop);
}
void
-pulse_output_set_mixer(struct pulse_output *po, struct pulse_mixer *pm)
+pulse_output_set_mixer(PulseOutput *po, PulseMixer *pm)
{
- assert(po != NULL);
- assert(po->mixer == NULL);
- assert(pm != NULL);
+ assert(po != nullptr);
+ assert(po->mixer == nullptr);
+ assert(pm != nullptr);
po->mixer = pm;
- if (po->mainloop == NULL)
+ if (po->mainloop == nullptr)
return;
pa_threaded_mainloop_lock(po->mainloop);
- if (po->context != NULL &&
+ if (po->context != nullptr &&
pa_context_get_state(po->context) == PA_CONTEXT_READY) {
pulse_mixer_on_connect(pm, po->context);
- if (po->stream != NULL &&
+ if (po->stream != nullptr &&
pa_stream_get_state(po->stream) == PA_STREAM_READY)
pulse_mixer_on_change(pm, po->context, po->stream);
}
@@ -117,23 +117,22 @@ pulse_output_set_mixer(struct pulse_output *po, struct pulse_mixer *pm)
}
void
-pulse_output_clear_mixer(struct pulse_output *po,
- G_GNUC_UNUSED struct pulse_mixer *pm)
+pulse_output_clear_mixer(PulseOutput *po, gcc_unused PulseMixer *pm)
{
- assert(po != NULL);
- assert(pm != NULL);
+ assert(po != nullptr);
+ assert(pm != nullptr);
assert(po->mixer == pm);
- po->mixer = NULL;
+ po->mixer = nullptr;
}
bool
-pulse_output_set_volume(struct pulse_output *po,
+pulse_output_set_volume(PulseOutput *po,
const struct pa_cvolume *volume, GError **error_r)
{
pa_operation *o;
- if (po->context == NULL || po->stream == NULL ||
+ 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");
return false;
@@ -141,8 +140,8 @@ pulse_output_set_volume(struct pulse_output *po,
o = pa_context_set_sink_input_volume(po->context,
pa_stream_get_index(po->stream),
- volume, NULL, NULL);
- if (o == NULL) {
+ 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)));
@@ -166,8 +165,8 @@ pulse_wait_for_operation(struct pa_threaded_mainloop *mainloop,
{
pa_operation_state_t state;
- assert(mainloop != NULL);
- assert(operation != NULL);
+ assert(mainloop != nullptr);
+ assert(operation != nullptr);
state = pa_operation_get_state(operation);
while (state == PA_OPERATION_RUNNING) {
@@ -188,7 +187,7 @@ static void
pulse_output_stream_success_cb(G_GNUC_UNUSED pa_stream *s,
G_GNUC_UNUSED int success, void *userdata)
{
- struct pulse_output *po = userdata;
+ PulseOutput *po = (PulseOutput *)userdata;
pa_threaded_mainloop_signal(po->mainloop, 0);
}
@@ -196,11 +195,11 @@ pulse_output_stream_success_cb(G_GNUC_UNUSED pa_stream *s,
static void
pulse_output_context_state_cb(struct pa_context *context, void *userdata)
{
- struct pulse_output *po = userdata;
+ PulseOutput *po = (PulseOutput *)userdata;
switch (pa_context_get_state(context)) {
case PA_CONTEXT_READY:
- if (po->mixer != NULL)
+ if (po->mixer != nullptr)
pulse_mixer_on_connect(po->mixer, context);
pa_threaded_mainloop_signal(po->mainloop, 0);
@@ -208,7 +207,7 @@ pulse_output_context_state_cb(struct pa_context *context, void *userdata)
case PA_CONTEXT_TERMINATED:
case PA_CONTEXT_FAILED:
- if (po->mixer != NULL)
+ if (po->mixer != nullptr)
pulse_mixer_on_disconnect(po->mixer);
/* the caller thread might be waiting for these
@@ -229,15 +228,15 @@ pulse_output_subscribe_cb(pa_context *context,
pa_subscription_event_type_t t,
uint32_t idx, void *userdata)
{
- struct pulse_output *po = userdata;
- pa_subscription_event_type_t facility
- = t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
- pa_subscription_event_type_t type
- = t & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
+ PulseOutput *po = (PulseOutput *)userdata;
+ pa_subscription_event_type_t facility =
+ pa_subscription_event_type_t(t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK);
+ pa_subscription_event_type_t type =
+ pa_subscription_event_type_t(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK);
- if (po->mixer != NULL &&
+ if (po->mixer != nullptr &&
facility == PA_SUBSCRIPTION_EVENT_SINK_INPUT &&
- po->stream != NULL &&
+ po->stream != nullptr &&
pa_stream_get_state(po->stream) == PA_STREAM_READY &&
idx == pa_stream_get_index(po->stream) &&
(type == PA_SUBSCRIPTION_EVENT_NEW ||
@@ -251,15 +250,15 @@ pulse_output_subscribe_cb(pa_context *context,
* @return true on success, false on error
*/
static bool
-pulse_output_connect(struct pulse_output *po, GError **error_r)
+pulse_output_connect(PulseOutput *po, GError **error_r)
{
- assert(po != NULL);
- assert(po->context != NULL);
+ assert(po != nullptr);
+ assert(po->context != nullptr);
int error;
error = pa_context_connect(po->context, po->server,
- (pa_context_flags_t)0, NULL);
+ (pa_context_flags_t)0, nullptr);
if (error < 0) {
g_set_error(error_r, pulse_output_quark(), 0,
"pa_context_connect() has failed: %s",
@@ -274,21 +273,21 @@ pulse_output_connect(struct pulse_output *po, GError **error_r)
* Frees and clears the stream.
*/
static void
-pulse_output_delete_stream(struct pulse_output *po)
+pulse_output_delete_stream(PulseOutput *po)
{
- assert(po != NULL);
- assert(po->stream != NULL);
+ assert(po != nullptr);
+ assert(po->stream != nullptr);
#if PA_CHECK_VERSION(0,9,8)
- pa_stream_set_suspended_callback(po->stream, NULL, NULL);
+ pa_stream_set_suspended_callback(po->stream, nullptr, nullptr);
#endif
- pa_stream_set_state_callback(po->stream, NULL, NULL);
- pa_stream_set_write_callback(po->stream, NULL, NULL);
+ pa_stream_set_state_callback(po->stream, nullptr, nullptr);
+ pa_stream_set_write_callback(po->stream, nullptr, nullptr);
pa_stream_disconnect(po->stream);
pa_stream_unref(po->stream);
- po->stream = NULL;
+ po->stream = nullptr;
}
/**
@@ -297,17 +296,17 @@ pulse_output_delete_stream(struct pulse_output *po)
* Caller must lock the main loop.
*/
static void
-pulse_output_delete_context(struct pulse_output *po)
+pulse_output_delete_context(PulseOutput *po)
{
- assert(po != NULL);
- assert(po->context != NULL);
+ assert(po != nullptr);
+ assert(po->context != nullptr);
- pa_context_set_state_callback(po->context, NULL, NULL);
- pa_context_set_subscribe_callback(po->context, NULL, NULL);
+ pa_context_set_state_callback(po->context, nullptr, nullptr);
+ pa_context_set_subscribe_callback(po->context, nullptr, nullptr);
pa_context_disconnect(po->context);
pa_context_unref(po->context);
- po->context = NULL;
+ po->context = nullptr;
}
/**
@@ -318,14 +317,14 @@ pulse_output_delete_context(struct pulse_output *po)
* @return true on success, false on error
*/
static bool
-pulse_output_setup_context(struct pulse_output *po, GError **error_r)
+pulse_output_setup_context(PulseOutput *po, GError **error_r)
{
- assert(po != NULL);
- assert(po->mainloop != NULL);
+ assert(po != nullptr);
+ assert(po->mainloop != nullptr);
po->context = pa_context_new(pa_threaded_mainloop_get_api(po->mainloop),
MPD_PULSE_NAME);
- if (po->context == NULL) {
+ if (po->context == nullptr) {
g_set_error(error_r, pulse_output_quark(), 0,
"pa_context_new() has failed");
return false;
@@ -345,26 +344,26 @@ pulse_output_setup_context(struct pulse_output *po, GError **error_r)
}
static struct audio_output *
-pulse_output_init(const struct config_param *param, GError **error_r)
+pulse_output_init(const config_param &param, GError **error_r)
{
- struct pulse_output *po;
+ PulseOutput *po;
g_setenv("PULSE_PROP_media.role", "music", true);
- po = g_new(struct pulse_output, 1);
+ po = new PulseOutput();
if (!ao_base_init(&po->base, &pulse_output_plugin, param, error_r)) {
- g_free(po);
- return NULL;
+ delete po;
+ return nullptr;
}
- po->name = config_get_block_string(param, "name", "mpd_pulse");
- po->server = config_get_block_string(param, "server", NULL);
- po->sink = config_get_block_string(param, "sink", NULL);
+ po->name = param.GetBlockValue("name", "mpd_pulse");
+ po->server = param.GetBlockValue("server");
+ po->sink = param.GetBlockValue("sink");
- po->mixer = NULL;
- po->mainloop = NULL;
- po->context = NULL;
- po->stream = NULL;
+ po->mixer = nullptr;
+ po->mainloop = nullptr;
+ po->context = nullptr;
+ po->stream = nullptr;
return &po->base;
}
@@ -372,24 +371,24 @@ pulse_output_init(const struct config_param *param, GError **error_r)
static void
pulse_output_finish(struct audio_output *ao)
{
- struct pulse_output *po = (struct pulse_output *)ao;
+ PulseOutput *po = (PulseOutput *)ao;
ao_base_finish(&po->base);
- g_free(po);
+ delete po;
}
static bool
pulse_output_enable(struct audio_output *ao, GError **error_r)
{
- struct pulse_output *po = (struct pulse_output *)ao;
+ PulseOutput *po = (PulseOutput *)ao;
- assert(po->mainloop == NULL);
- assert(po->context == NULL);
+ assert(po->mainloop == nullptr);
+ assert(po->context == nullptr);
/* create the libpulse mainloop and start the thread */
po->mainloop = pa_threaded_mainloop_new();
- if (po->mainloop == NULL) {
+ if (po->mainloop == nullptr) {
g_free(po);
g_set_error(error_r, pulse_output_quark(), 0,
@@ -402,7 +401,7 @@ pulse_output_enable(struct audio_output *ao, GError **error_r)
if (pa_threaded_mainloop_start(po->mainloop) < 0) {
pa_threaded_mainloop_unlock(po->mainloop);
pa_threaded_mainloop_free(po->mainloop);
- po->mainloop = NULL;
+ po->mainloop = nullptr;
g_set_error(error_r, pulse_output_quark(), 0,
"pa_threaded_mainloop_start() has failed");
@@ -415,7 +414,7 @@ pulse_output_enable(struct audio_output *ao, GError **error_r)
pa_threaded_mainloop_unlock(po->mainloop);
pa_threaded_mainloop_stop(po->mainloop);
pa_threaded_mainloop_free(po->mainloop);
- po->mainloop = NULL;
+ po->mainloop = nullptr;
return false;
}
@@ -427,15 +426,15 @@ pulse_output_enable(struct audio_output *ao, GError **error_r)
static void
pulse_output_disable(struct audio_output *ao)
{
- struct pulse_output *po = (struct pulse_output *)ao;
+ PulseOutput *po = (PulseOutput *)ao;
- assert(po->mainloop != NULL);
+ assert(po->mainloop != nullptr);
pa_threaded_mainloop_stop(po->mainloop);
- if (po->context != NULL)
+ if (po->context != nullptr)
pulse_output_delete_context(po);
pa_threaded_mainloop_free(po->mainloop);
- po->mainloop = NULL;
+ po->mainloop = nullptr;
}
/**
@@ -447,13 +446,13 @@ pulse_output_disable(struct audio_output *ao)
* @return true on success, false on error
*/
static bool
-pulse_output_wait_connection(struct pulse_output *po, GError **error_r)
+pulse_output_wait_connection(PulseOutput *po, GError **error_r)
{
- assert(po->mainloop != NULL);
+ assert(po->mainloop != nullptr);
pa_context_state_t state;
- if (po->context == NULL && !pulse_output_setup_context(po, error_r))
+ if (po->context == nullptr && !pulse_output_setup_context(po, error_r))
return false;
while (true) {
@@ -488,10 +487,10 @@ pulse_output_wait_connection(struct pulse_output *po, GError **error_r)
static void
pulse_output_stream_suspended_cb(G_GNUC_UNUSED pa_stream *stream, void *userdata)
{
- struct pulse_output *po = userdata;
+ PulseOutput *po = (PulseOutput *)userdata;
- assert(stream == po->stream || po->stream == NULL);
- assert(po->mainloop != NULL);
+ assert(stream == po->stream || po->stream == nullptr);
+ assert(po->mainloop != nullptr);
/* wake up the main loop to break out of the loop in
pulse_output_play() */
@@ -503,15 +502,15 @@ pulse_output_stream_suspended_cb(G_GNUC_UNUSED pa_stream *stream, void *userdata
static void
pulse_output_stream_state_cb(pa_stream *stream, void *userdata)
{
- struct pulse_output *po = userdata;
+ PulseOutput *po = (PulseOutput *)userdata;
- assert(stream == po->stream || po->stream == NULL);
- assert(po->mainloop != NULL);
- assert(po->context != NULL);
+ assert(stream == po->stream || po->stream == nullptr);
+ assert(po->mainloop != nullptr);
+ assert(po->context != nullptr);
switch (pa_stream_get_state(stream)) {
case PA_STREAM_READY:
- if (po->mixer != NULL)
+ if (po->mixer != nullptr)
pulse_mixer_on_change(po->mixer, po->context, stream);
pa_threaded_mainloop_signal(po->mainloop, 0);
@@ -519,7 +518,7 @@ pulse_output_stream_state_cb(pa_stream *stream, void *userdata)
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED:
- if (po->mixer != NULL)
+ if (po->mixer != nullptr)
pulse_mixer_on_disconnect(po->mixer);
pa_threaded_mainloop_signal(po->mainloop, 0);
@@ -535,9 +534,9 @@ static void
pulse_output_stream_write_cb(G_GNUC_UNUSED pa_stream *stream, size_t nbytes,
void *userdata)
{
- struct pulse_output *po = userdata;
+ PulseOutput *po = (PulseOutput *)userdata;
- assert(po->mainloop != NULL);
+ assert(po->mainloop != nullptr);
po->writable = nbytes;
pa_threaded_mainloop_signal(po->mainloop, 0);
@@ -551,14 +550,14 @@ pulse_output_stream_write_cb(G_GNUC_UNUSED pa_stream *stream, size_t nbytes,
* @return true on success, false on error
*/
static bool
-pulse_output_setup_stream(struct pulse_output *po, const pa_sample_spec *ss,
+pulse_output_setup_stream(PulseOutput *po, const pa_sample_spec *ss,
GError **error_r)
{
- assert(po != NULL);
- assert(po->context != NULL);
+ assert(po != nullptr);
+ assert(po->context != nullptr);
- po->stream = pa_stream_new(po->context, po->name, ss, NULL);
- if (po->stream == NULL) {
+ 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)));
@@ -579,18 +578,18 @@ pulse_output_setup_stream(struct pulse_output *po, const pa_sample_spec *ss,
}
static bool
-pulse_output_open(struct audio_output *ao, struct audio_format *audio_format,
+pulse_output_open(struct audio_output *ao, AudioFormat &audio_format,
GError **error_r)
{
- struct pulse_output *po = (struct pulse_output *)ao;
+ PulseOutput *po = (PulseOutput *)ao;
pa_sample_spec ss;
int error;
- assert(po->mainloop != NULL);
+ assert(po->mainloop != nullptr);
pa_threaded_mainloop_lock(po->mainloop);
- if (po->context != NULL) {
+ if (po->context != nullptr) {
switch (pa_context_get_state(po->context)) {
case PA_CONTEXT_UNCONNECTED:
case PA_CONTEXT_TERMINATED:
@@ -616,11 +615,11 @@ pulse_output_open(struct audio_output *ao, struct audio_format *audio_format,
/* MPD doesn't support the other pulseaudio sample formats, so
we just force MPD to send us everything as 16 bit */
- audio_format->format = SAMPLE_FORMAT_S16;
+ audio_format.format = SampleFormat::S16;
ss.format = PA_SAMPLE_S16NE;
- ss.rate = audio_format->sample_rate;
- ss.channels = audio_format->channels;
+ ss.rate = audio_format.sample_rate;
+ ss.channels = audio_format.channels;
/* create a stream .. */
@@ -632,7 +631,8 @@ pulse_output_open(struct audio_output *ao, struct audio_format *audio_format,
/* .. and connect it (asynchronously) */
error = pa_stream_connect_playback(po->stream, po->sink,
- NULL, 0, NULL, NULL);
+ nullptr, pa_stream_flags_t(0),
+ nullptr, nullptr);
if (error < 0) {
pulse_output_delete_stream(po);
@@ -655,17 +655,17 @@ pulse_output_open(struct audio_output *ao, struct audio_format *audio_format,
static void
pulse_output_close(struct audio_output *ao)
{
- struct pulse_output *po = (struct pulse_output *)ao;
+ PulseOutput *po = (PulseOutput *)ao;
pa_operation *o;
- assert(po->mainloop != NULL);
+ assert(po->mainloop != nullptr);
pa_threaded_mainloop_lock(po->mainloop);
if (pa_stream_get_state(po->stream) == PA_STREAM_READY) {
o = pa_stream_drain(po->stream,
pulse_output_stream_success_cb, po);
- if (o == NULL) {
+ if (o == nullptr) {
g_warning("pa_stream_drain() has failed: %s",
pa_strerror(pa_context_errno(po->context)));
} else
@@ -674,7 +674,7 @@ pulse_output_close(struct audio_output *ao)
pulse_output_delete_stream(po);
- if (po->context != NULL &&
+ if (po->context != nullptr &&
pa_context_get_state(po->context) != PA_CONTEXT_READY)
pulse_output_delete_context(po);
@@ -688,7 +688,7 @@ pulse_output_close(struct audio_output *ao)
* @return true on success, false on error
*/
static bool
-pulse_output_wait_stream(struct pulse_output *po, GError **error_r)
+pulse_output_wait_stream(PulseOutput *po, GError **error_r)
{
while (true) {
switch (pa_stream_get_state(po->stream)) {
@@ -716,9 +716,9 @@ pulse_output_wait_stream(struct pulse_output *po, GError **error_r)
* 0.9.11, it uses a custom pause flag.
*/
static bool
-pulse_output_stream_is_paused(struct pulse_output *po)
+pulse_output_stream_is_paused(PulseOutput *po)
{
- assert(po->stream != NULL);
+ assert(po->stream != nullptr);
#if !defined(PA_CHECK_VERSION) || !PA_CHECK_VERSION(0,9,11)
return po->pause;
@@ -731,18 +731,18 @@ pulse_output_stream_is_paused(struct pulse_output *po)
* Sets cork mode on the stream.
*/
static bool
-pulse_output_stream_pause(struct pulse_output *po, bool pause,
+pulse_output_stream_pause(PulseOutput *po, bool pause,
GError **error_r)
{
pa_operation *o;
- assert(po->mainloop != NULL);
- assert(po->context != NULL);
- assert(po->stream != NULL);
+ assert(po->mainloop != nullptr);
+ assert(po->context != nullptr);
+ assert(po->stream != nullptr);
o = pa_stream_cork(po->stream, pause,
pulse_output_stream_success_cb, po);
- if (o == NULL) {
+ 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)));
@@ -765,7 +765,7 @@ pulse_output_stream_pause(struct pulse_output *po, bool pause,
static unsigned
pulse_output_delay(struct audio_output *ao)
{
- struct pulse_output *po = (struct pulse_output *)ao;
+ PulseOutput *po = (PulseOutput *)ao;
unsigned result = 0;
pa_threaded_mainloop_lock(po->mainloop);
@@ -784,11 +784,11 @@ static size_t
pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error_r)
{
- struct pulse_output *po = (struct pulse_output *)ao;
+ PulseOutput *po = (PulseOutput *)ao;
int error;
- assert(po->mainloop != NULL);
- assert(po->stream != NULL);
+ assert(po->mainloop != nullptr);
+ assert(po->stream != nullptr);
pa_threaded_mainloop_lock(po->mainloop);
@@ -799,7 +799,7 @@ pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
return 0;
}
- assert(po->context != NULL);
+ assert(po->context != nullptr);
/* unpause if previously paused */
@@ -839,7 +839,7 @@ pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
po->writable -= size;
- error = pa_stream_write(po->stream, chunk, size, NULL,
+ error = pa_stream_write(po->stream, chunk, size, nullptr,
0, PA_SEEK_RELATIVE);
pa_threaded_mainloop_unlock(po->mainloop);
if (error < 0) {
@@ -854,11 +854,11 @@ pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
static void
pulse_output_cancel(struct audio_output *ao)
{
- struct pulse_output *po = (struct pulse_output *)ao;
+ PulseOutput *po = (PulseOutput *)ao;
pa_operation *o;
- assert(po->mainloop != NULL);
- assert(po->stream != NULL);
+ assert(po->mainloop != nullptr);
+ assert(po->stream != nullptr);
pa_threaded_mainloop_lock(po->mainloop);
@@ -869,10 +869,10 @@ pulse_output_cancel(struct audio_output *ao)
return;
}
- assert(po->context != NULL);
+ assert(po->context != nullptr);
o = pa_stream_flush(po->stream, pulse_output_stream_success_cb, po);
- if (o == NULL) {
+ if (o == nullptr) {
g_warning("pa_stream_flush() has failed: %s",
pa_strerror(pa_context_errno(po->context)));
pa_threaded_mainloop_unlock(po->mainloop);
@@ -886,11 +886,11 @@ pulse_output_cancel(struct audio_output *ao)
static bool
pulse_output_pause(struct audio_output *ao)
{
- struct pulse_output *po = (struct pulse_output *)ao;
- GError *error = NULL;
+ PulseOutput *po = (PulseOutput *)ao;
+ GError *error = nullptr;
- assert(po->mainloop != NULL);
- assert(po->stream != NULL);
+ assert(po->mainloop != nullptr);
+ assert(po->stream != nullptr);
pa_threaded_mainloop_lock(po->mainloop);
@@ -903,7 +903,7 @@ pulse_output_pause(struct audio_output *ao)
return false;
}
- assert(po->context != NULL);
+ assert(po->context != nullptr);
/* cork the stream */
@@ -923,33 +923,34 @@ pulse_output_pause(struct audio_output *ao)
static bool
pulse_output_test_default_device(void)
{
- struct pulse_output *po;
bool success;
- po = (struct pulse_output *)pulse_output_init(NULL, NULL);
- if (po == NULL)
+ const config_param empty;
+ PulseOutput *po = (PulseOutput *)pulse_output_init(empty, nullptr);
+ if (po == nullptr)
return false;
- success = pulse_output_wait_connection(po, NULL);
+ success = pulse_output_wait_connection(po, nullptr);
pulse_output_finish(&po->base);
return success;
}
const struct audio_output_plugin pulse_output_plugin = {
- .name = "pulse",
-
- .test_default_device = pulse_output_test_default_device,
- .init = pulse_output_init,
- .finish = pulse_output_finish,
- .enable = pulse_output_enable,
- .disable = pulse_output_disable,
- .open = pulse_output_open,
- .delay = pulse_output_delay,
- .play = pulse_output_play,
- .cancel = pulse_output_cancel,
- .pause = pulse_output_pause,
- .close = pulse_output_close,
-
- .mixer_plugin = &pulse_mixer_plugin,
+ "pulse",
+ pulse_output_test_default_device,
+ pulse_output_init,
+ pulse_output_finish,
+ pulse_output_enable,
+ pulse_output_disable,
+ pulse_output_open,
+ pulse_output_close,
+ pulse_output_delay,
+ nullptr,
+ pulse_output_play,
+ nullptr,
+ pulse_output_cancel,
+ pulse_output_pause,
+
+ &pulse_mixer_plugin,
};
diff --git a/src/output/pulse_output_plugin.h b/src/output/PulseOutputPlugin.hxx
index 02a51f27b..58dc6703c 100644
--- a/src/output/pulse_output_plugin.h
+++ b/src/output/PulseOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,33 +17,39 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_PULSE_OUTPUT_PLUGIN_H
-#define MPD_PULSE_OUTPUT_PLUGIN_H
+#ifndef MPD_PULSE_OUTPUT_PLUGIN_HXX
+#define MPD_PULSE_OUTPUT_PLUGIN_HXX
-#include <stdbool.h>
+#include "gerror.h"
-#include <glib.h>
-
-struct pulse_output;
-struct pulse_mixer;
+struct PulseOutput;
+struct PulseMixer;
struct pa_cvolume;
extern const struct audio_output_plugin pulse_output_plugin;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void
-pulse_output_lock(struct pulse_output *po);
+pulse_output_lock(PulseOutput *po);
void
-pulse_output_unlock(struct pulse_output *po);
+pulse_output_unlock(PulseOutput *po);
void
-pulse_output_set_mixer(struct pulse_output *po, struct pulse_mixer *pm);
+pulse_output_set_mixer(PulseOutput *po, PulseMixer *pm);
void
-pulse_output_clear_mixer(struct pulse_output *po, struct pulse_mixer *pm);
+pulse_output_clear_mixer(PulseOutput *po, PulseMixer *pm);
bool
-pulse_output_set_volume(struct pulse_output *po,
+pulse_output_set_volume(PulseOutput *po,
const struct pa_cvolume *volume, GError **error_r);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/output/recorder_output_plugin.c b/src/output/RecorderOutputPlugin.cxx
index b84cb244c..afae17e84 100644
--- a/src/output/recorder_output_plugin.c
+++ b/src/output/RecorderOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,10 +18,10 @@
*/
#include "config.h"
-#include "recorder_output_plugin.h"
-#include "output_api.h"
-#include "encoder_plugin.h"
-#include "encoder_list.h"
+#include "RecorderOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "EncoderPlugin.hxx"
+#include "EncoderList.hxx"
#include "fd_util.h"
#include "open.h"
@@ -34,13 +34,13 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "recorder"
-struct recorder_output {
+struct RecorderOutput {
struct audio_output base;
/**
* The configured encoder plugin.
*/
- struct encoder *encoder;
+ Encoder *encoder;
/**
* The destination file name.
@@ -56,6 +56,24 @@ struct recorder_output {
* The buffer for encoder_read().
*/
char buffer[32768];
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &recorder_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
+
+ bool Configure(const config_param &param, GError **error_r);
+
+ bool WriteToFile(const void *data, size_t length, GError **error_r);
+
+ /**
+ * Writes pending data from the encoder to the output file.
+ */
+ bool EncoderToFile(GError **error_r);
};
/**
@@ -67,68 +85,70 @@ recorder_output_quark(void)
return g_quark_from_static_string("recorder_output");
}
-static struct audio_output *
-recorder_output_init(const struct config_param *param, GError **error_r)
+inline bool
+RecorderOutput::Configure(const config_param &param, GError **error_r)
{
- struct recorder_output *recorder = g_new(struct recorder_output, 1);
- if (!ao_base_init(&recorder->base, &recorder_output_plugin, param,
- error_r)) {
- g_free(recorder);
- return NULL;
- }
-
/* read configuration */
const char *encoder_name =
- config_get_block_string(param, "encoder", "vorbis");
- const struct encoder_plugin *encoder_plugin =
- encoder_plugin_get(encoder_name);
- if (encoder_plugin == NULL) {
+ 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);
- goto failure;
+ return false;
}
- recorder->path = config_get_block_string(param, "path", NULL);
- if (recorder->path == NULL) {
+ path = param.GetBlockValue("path");
+ if (path == nullptr) {
g_set_error(error_r, recorder_output_quark(), 0,
"'path' not configured");
- goto failure;
+ return false;
}
/* initialize encoder */
- recorder->encoder = encoder_init(encoder_plugin, param, error_r);
- if (recorder->encoder == NULL)
- goto failure;
+ encoder = encoder_init(*encoder_plugin, param, error_r);
+ if (encoder == nullptr)
+ return false;
- return &recorder->base;
+ return true;
+}
+
+static audio_output *
+recorder_output_init(const config_param &param, GError **error_r)
+{
+ RecorderOutput *recorder = new RecorderOutput();
+
+ if (!recorder->Initialize(param, error_r)) {
+ delete recorder;
+ return nullptr;
+ }
+
+ if (!recorder->Configure(param, error_r)) {
+ recorder->Deinitialize();
+ delete recorder;
+ return nullptr;
+ }
-failure:
- ao_base_finish(&recorder->base);
- g_free(recorder);
- return NULL;
+ return &recorder->base;
}
static void
recorder_output_finish(struct audio_output *ao)
{
- struct recorder_output *recorder = (struct recorder_output *)ao;
+ RecorderOutput *recorder = (RecorderOutput *)ao;
encoder_finish(recorder->encoder);
- ao_base_finish(&recorder->base);
- g_free(recorder);
+ recorder->Deinitialize();
+ delete recorder;
}
-static bool
-recorder_write_to_file(struct recorder_output *recorder,
- const void *_data, size_t length,
- GError **error_r)
+inline bool
+RecorderOutput::WriteToFile(const void *_data, size_t length, GError **error_r)
{
assert(length > 0);
- const int fd = recorder->fd;
-
const uint8_t *data = (const uint8_t *)_data, *end = data + length;
while (true) {
@@ -145,43 +165,37 @@ recorder_write_to_file(struct recorder_output *recorder,
} else if (errno != EINTR) {
g_set_error(error_r, recorder_output_quark(), 0,
"Failed to write to '%s': %s",
- recorder->path, g_strerror(errno));
+ path, g_strerror(errno));
return false;
}
}
}
-/**
- * Writes pending data from the encoder to the output file.
- */
-static bool
-recorder_output_encoder_to_file(struct recorder_output *recorder,
- GError **error_r)
+inline bool
+RecorderOutput::EncoderToFile(GError **error_r)
{
- assert(recorder->fd >= 0);
+ assert(fd >= 0);
while (true) {
/* read from the encoder */
- size_t size = encoder_read(recorder->encoder, recorder->buffer,
- sizeof(recorder->buffer));
+ size_t size = encoder_read(encoder, buffer, sizeof(buffer));
if (size == 0)
return true;
/* write everything into the file */
- if (!recorder_write_to_file(recorder, recorder->buffer, size,
- error_r))
+ if (!WriteToFile(buffer, size, error_r))
return false;
}
}
static bool
recorder_output_open(struct audio_output *ao,
- struct audio_format *audio_format,
+ AudioFormat &audio_format,
GError **error_r)
{
- struct recorder_output *recorder = (struct recorder_output *)ao;
+ RecorderOutput *recorder = (RecorderOutput *)ao;
/* create the output file */
@@ -203,7 +217,7 @@ recorder_output_open(struct audio_output *ao,
return false;
}
- if (!recorder_output_encoder_to_file(recorder, error_r)) {
+ if (!recorder->EncoderToFile(error_r)) {
encoder_close(recorder->encoder);
close(recorder->fd);
unlink(recorder->path);
@@ -216,12 +230,12 @@ recorder_output_open(struct audio_output *ao,
static void
recorder_output_close(struct audio_output *ao)
{
- struct recorder_output *recorder = (struct recorder_output *)ao;
+ RecorderOutput *recorder = (RecorderOutput *)ao;
/* flush the encoder and write the rest to the file */
- if (encoder_end(recorder->encoder, NULL))
- recorder_output_encoder_to_file(recorder, NULL);
+ if (encoder_end(recorder->encoder, nullptr))
+ recorder->EncoderToFile(nullptr);
/* now really close everything */
@@ -234,18 +248,27 @@ static size_t
recorder_output_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error_r)
{
- struct recorder_output *recorder = (struct recorder_output *)ao;
+ RecorderOutput *recorder = (RecorderOutput *)ao;
return encoder_write(recorder->encoder, chunk, size, error_r) &&
- recorder_output_encoder_to_file(recorder, error_r)
+ recorder->EncoderToFile(error_r)
? size : 0;
}
const struct audio_output_plugin recorder_output_plugin = {
- .name = "recorder",
- .init = recorder_output_init,
- .finish = recorder_output_finish,
- .open = recorder_output_open,
- .close = recorder_output_close,
- .play = recorder_output_play,
+ "recorder",
+ nullptr,
+ recorder_output_init,
+ recorder_output_finish,
+ nullptr,
+ nullptr,
+ recorder_output_open,
+ recorder_output_close,
+ nullptr,
+ nullptr,
+ recorder_output_play,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
};
diff --git a/src/output/recorder_output_plugin.h b/src/output/RecorderOutputPlugin.hxx
index a9bf755bd..a27f51e23 100644
--- a/src/output/recorder_output_plugin.h
+++ b/src/output/RecorderOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_RECORDER_OUTPUT_PLUGIN_H
-#define MPD_RECORDER_OUTPUT_PLUGIN_H
+#ifndef MPD_RECORDER_OUTPUT_PLUGIN_HXX
+#define MPD_RECORDER_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin recorder_output_plugin;
diff --git a/src/output/roar_output_plugin.c b/src/output/RoarOutputPlugin.cxx
index 1c2c48321..36f7c395b 100644
--- a/src/output/roar_output_plugin.c
+++ b/src/output/RoarOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
* Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
*
@@ -19,25 +19,23 @@
*/
#include "config.h"
-#include "roar_output_plugin.h"
-#include "output_api.h"
-#include "mixer_list.h"
-#include "roar_output_plugin.h"
+#include "RoarOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "MixerList.hxx"
+#include "thread/Mutex.hxx"
#include <glib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
+/* libroar/services.h declares roar_service_stream::new - work around
+ this C++ problem */
+#define new _new
#include <roaraudio.h>
+#undef new
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "roaraudio"
-typedef struct roar
-{
+struct RoarOutput {
struct audio_output base;
roar_vs_t * vss;
@@ -47,9 +45,18 @@ typedef struct roar
int role;
struct roar_connection con;
struct roar_audio_info info;
- GMutex *lock;
+ Mutex mutex;
volatile bool alive;
-} roar_t;
+
+ RoarOutput()
+ :err(ROAR_ERROR_NONE),
+ host(nullptr), name(nullptr) {}
+
+ ~RoarOutput() {
+ g_free(host);
+ g_free(name);
+ }
+};
static inline GQuark
roar_output_quark(void)
@@ -58,9 +65,9 @@ roar_output_quark(void)
}
static int
-roar_output_get_volume_locked(struct roar *roar)
+roar_output_get_volume_locked(RoarOutput *roar)
{
- if (roar->vss == NULL || !roar->alive)
+ if (roar->vss == nullptr || !roar->alive)
return -1;
float l, r;
@@ -72,20 +79,18 @@ roar_output_get_volume_locked(struct roar *roar)
}
int
-roar_output_get_volume(struct roar *roar)
+roar_output_get_volume(RoarOutput *roar)
{
- g_mutex_lock(roar->lock);
- int volume = roar_output_get_volume_locked(roar);
- g_mutex_unlock(roar->lock);
- return volume;
+ const ScopeLock protect(roar->mutex);
+ return roar_output_get_volume_locked(roar);
}
static bool
-roar_output_set_volume_locked(struct roar *roar, unsigned volume)
+roar_output_set_volume_locked(RoarOutput *roar, unsigned volume)
{
assert(volume <= 100);
- if (roar->vss == NULL || !roar->alive)
+ if (roar->vss == nullptr || !roar->alive)
return false;
int error;
@@ -96,38 +101,34 @@ roar_output_set_volume_locked(struct roar *roar, unsigned volume)
}
bool
-roar_output_set_volume(struct roar *roar, unsigned volume)
+roar_output_set_volume(RoarOutput *roar, unsigned volume)
{
- g_mutex_lock(roar->lock);
- bool success = roar_output_set_volume_locked(roar, volume);
- g_mutex_unlock(roar->lock);
- return success;
+ const ScopeLock protect(roar->mutex);
+ return roar_output_set_volume_locked(roar, volume);
}
static void
-roar_configure(struct roar * self, const struct config_param *param)
+roar_configure(RoarOutput *self, const config_param &param)
{
- self->host = config_dup_block_string(param, "server", NULL);
- self->name = config_dup_block_string(param, "name", "MPD");
+ self->host = param.DupBlockString("server", nullptr);
+ self->name = param.DupBlockString("name", "MPD");
- const char *role = config_get_block_string(param, "role", "music");
- self->role = role != NULL
+ const char *role = param.GetBlockValue("role", "music");
+ self->role = role != nullptr
? roar_str2role(role)
: ROAR_ROLE_MUSIC;
}
static struct audio_output *
-roar_init(const struct config_param *param, GError **error_r)
+roar_init(const config_param &param, GError **error_r)
{
- struct roar *self = g_new0(struct roar, 1);
+ RoarOutput *self = new RoarOutput();
if (!ao_base_init(&self->base, &roar_output_plugin, param, error_r)) {
- g_free(self);
- return NULL;
+ delete self;
+ return nullptr;
}
- self->lock = g_mutex_new();
- self->err = ROAR_ERROR_NONE;
roar_configure(self, param);
return &self->base;
}
@@ -135,70 +136,66 @@ roar_init(const struct config_param *param, GError **error_r)
static void
roar_finish(struct audio_output *ao)
{
- struct roar *self = (struct roar *)ao;
-
- g_free(self->host);
- g_free(self->name);
- g_mutex_free(self->lock);
+ RoarOutput *self = (RoarOutput *)ao;
ao_base_finish(&self->base);
- g_free(self);
+ delete self;
}
static void
roar_use_audio_format(struct roar_audio_info *info,
- struct audio_format *audio_format)
+ AudioFormat &audio_format)
{
- info->rate = audio_format->sample_rate;
- info->channels = audio_format->channels;
+ info->rate = audio_format.sample_rate;
+ info->channels = audio_format.channels;
info->codec = ROAR_CODEC_PCM_S;
- switch (audio_format->format) {
- case SAMPLE_FORMAT_UNDEFINED:
+ switch (audio_format.format) {
+ case SampleFormat::UNDEFINED:
+ case SampleFormat::FLOAT:
+ case SampleFormat::DSD:
info->bits = 16;
- audio_format->format = SAMPLE_FORMAT_S16;
+ audio_format.format = SampleFormat::S16;
break;
- case SAMPLE_FORMAT_S8:
+ case SampleFormat::S8:
info->bits = 8;
break;
- case SAMPLE_FORMAT_S16:
+ case SampleFormat::S16:
info->bits = 16;
break;
- case SAMPLE_FORMAT_S24_P32:
+ case SampleFormat::S24_P32:
info->bits = 32;
- audio_format->format = SAMPLE_FORMAT_S32;
+ audio_format.format = SampleFormat::S32;
break;
- case SAMPLE_FORMAT_S32:
+ case SampleFormat::S32:
info->bits = 32;
break;
}
}
static bool
-roar_open(struct audio_output *ao, struct audio_format *audio_format, GError **error)
+roar_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
{
- struct roar *self = (struct roar *)ao;
- g_mutex_lock(self->lock);
+ 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");
- g_mutex_unlock(self->lock);
return false;
}
self->vss = roar_vs_new_from_con(&(self->con), &(self->err));
- if (self->vss == NULL || self->err != ROAR_ERROR_NONE)
+ if (self->vss == nullptr || self->err != ROAR_ERROR_NONE)
{
g_set_error(error, roar_output_quark(), 0,
"Failed to connect to server");
- g_mutex_unlock(self->lock);
return false;
}
@@ -208,43 +205,41 @@ roar_open(struct audio_output *ao, struct audio_format *audio_format, GError **e
&(self->err)) < 0)
{
g_set_error(error, roar_output_quark(), 0, "Failed to start stream");
- g_mutex_unlock(self->lock);
return false;
}
roar_vs_role(self->vss, self->role, &(self->err));
self->alive = true;
- g_mutex_unlock(self->lock);
return true;
}
static void
roar_close(struct audio_output *ao)
{
- struct roar *self = (struct roar *)ao;
- g_mutex_lock(self->lock);
+ RoarOutput *self = (RoarOutput *)ao;
+ const ScopeLock protect(self->mutex);
+
self->alive = false;
- if (self->vss != NULL)
+ if (self->vss != nullptr)
roar_vs_close(self->vss, ROAR_VS_TRUE, &(self->err));
- self->vss = NULL;
+ self->vss = nullptr;
roar_disconnect(&(self->con));
- g_mutex_unlock(self->lock);
}
static void
-roar_cancel_locked(struct roar *self)
+roar_cancel_locked(RoarOutput *self)
{
- if (self->vss == NULL)
+ if (self->vss == nullptr)
return;
roar_vs_t *vss = self->vss;
- self->vss = NULL;
+ self->vss = nullptr;
roar_vs_close(vss, ROAR_VS_TRUE, &(self->err));
self->alive = false;
vss = roar_vs_new_from_con(&(self->con), &(self->err));
- if (vss == NULL)
+ if (vss == nullptr)
return;
if (roar_vs_stream(vss, &(self->info), ROAR_DIR_PLAY,
@@ -262,20 +257,19 @@ roar_cancel_locked(struct roar *self)
static void
roar_cancel(struct audio_output *ao)
{
- struct roar *self = (struct roar *)ao;
+ RoarOutput *self = (RoarOutput *)ao;
- g_mutex_lock(self->lock);
+ const ScopeLock protect(self->mutex);
roar_cancel_locked(self);
- g_mutex_unlock(self->lock);
}
static size_t
roar_play(struct audio_output *ao, const void *chunk, size_t size, GError **error)
{
- struct roar *self = (struct roar *)ao;
+ RoarOutput *self = (RoarOutput *)ao;
ssize_t rc;
- if (self->vss == NULL)
+ if (self->vss == nullptr)
{
g_set_error(error, roar_output_quark(), 0, "Connection is invalid");
return 0;
@@ -332,19 +326,20 @@ roar_tag_convert(enum tag_type type, bool *is_uuid)
return "HASH";
default:
- return NULL;
+ return nullptr;
}
}
static void
-roar_send_tag(struct audio_output *ao, const struct tag *meta)
+roar_send_tag(struct audio_output *ao, const Tag *meta)
{
- struct roar *self = (struct roar *)ao;
+ RoarOutput *self = (RoarOutput *)ao;
- if (self->vss == NULL)
+ if (self->vss == nullptr)
return;
- g_mutex_lock(self->lock);
+ const ScopeLock protect(self->mutex);
+
size_t cnt = 1;
struct roar_keyval vals[32];
memset(vals, 0, sizeof(vals));
@@ -361,7 +356,7 @@ roar_send_tag(struct audio_output *ao, const struct tag *meta)
{
bool is_uuid = false;
const char *key = roar_tag_convert(meta->items[i]->type, &is_uuid);
- if (key != NULL)
+ if (key != nullptr)
{
if (is_uuid)
{
@@ -383,19 +378,22 @@ roar_send_tag(struct audio_output *ao, const struct tag *meta)
for (unsigned i = 0; i < 32; i++)
g_free(vals[i].key);
-
- g_mutex_unlock(self->lock);
}
const struct audio_output_plugin roar_output_plugin = {
- .name = "roar",
- .init = roar_init,
- .finish = roar_finish,
- .open = roar_open,
- .play = roar_play,
- .cancel = roar_cancel,
- .close = roar_close,
- .send_tag = roar_send_tag,
-
- .mixer_plugin = &roar_mixer_plugin
+ "roar",
+ nullptr,
+ roar_init,
+ roar_finish,
+ nullptr,
+ nullptr,
+ roar_open,
+ roar_close,
+ nullptr,
+ roar_send_tag,
+ roar_play,
+ nullptr,
+ roar_cancel,
+ nullptr,
+ &roar_mixer_plugin,
};
diff --git a/src/output/roar_output_plugin.h b/src/output/RoarOutputPlugin.hxx
index 78b628cc4..faa4b4d5c 100644
--- a/src/output/roar_output_plugin.h
+++ b/src/output/RoarOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,16 +20,14 @@
#ifndef MPD_ROAR_OUTPUT_PLUGIN_H
#define MPD_ROAR_OUTPUT_PLUGIN_H
-#include <stdbool.h>
-
-struct roar;
+struct RoarOutput;
extern const struct audio_output_plugin roar_output_plugin;
int
-roar_output_get_volume(struct roar *roar);
+roar_output_get_volume(RoarOutput *roar);
bool
-roar_output_set_volume(struct roar *roar, unsigned volume);
+roar_output_set_volume(RoarOutput *roar, unsigned volume);
#endif
diff --git a/src/output/shout_output_plugin.c b/src/output/ShoutOutputPlugin.cxx
index 56456a0ea..2d2c0afd0 100644
--- a/src/output/shout_output_plugin.c
+++ b/src/output/ShoutOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,10 +18,10 @@
*/
#include "config.h"
-#include "shout_output_plugin.h"
-#include "output_api.h"
-#include "encoder_plugin.h"
-#include "encoder_list.h"
+#include "ShoutOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "EncoderPlugin.hxx"
+#include "EncoderList.hxx"
#include "mpd_error.h"
#include <shout/shout.h>
@@ -29,20 +29,21 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include <stdio.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "shout"
-#define DEFAULT_CONN_TIMEOUT 2
+static constexpr unsigned DEFAULT_CONN_TIMEOUT = 2;
-struct shout_data {
+struct ShoutOutput final {
struct audio_output base;
shout_t *shout_conn;
shout_metadata_t *shout_meta;
- struct encoder *encoder;
+ Encoder *encoder;
float quality;
int bitrate;
@@ -50,6 +51,31 @@ struct shout_data {
int timeout;
uint8_t buffer[32768];
+
+ ShoutOutput()
+ :shout_conn(shout_new()),
+ shout_meta(shout_metadata_new()),
+ quality(-2.0),
+ bitrate(-1),
+ timeout(DEFAULT_CONN_TIMEOUT) {}
+
+ ~ShoutOutput() {
+ if (shout_meta != nullptr)
+ shout_metadata_free(shout_meta);
+ if (shout_conn != nullptr)
+ shout_free(shout_conn);
+ }
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &shout_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
+
+ bool Configure(const config_param &param, GError **error_r);
};
static int shout_init_count;
@@ -63,7 +89,7 @@ shout_output_quark(void)
return g_quark_from_static_string("shout_output");
}
-static const struct encoder_plugin *
+static const EncoderPlugin *
shout_encoder_plugin_get(const char *name)
{
if (strcmp(name, "ogg") == 0)
@@ -74,137 +100,94 @@ shout_encoder_plugin_get(const char *name)
return encoder_plugin_get(name);
}
-static struct shout_data *new_shout_data(void)
+gcc_pure
+static const char *
+require_block_string(const config_param &param, const char *name)
{
- struct shout_data *ret = g_new(struct shout_data, 1);
-
- ret->shout_conn = shout_new();
- ret->shout_meta = shout_metadata_new();
- ret->bitrate = -1;
- ret->quality = -2.0;
- ret->timeout = DEFAULT_CONN_TIMEOUT;
+ const char *value = param.GetBlockValue(name);
+ if (value == nullptr)
+ MPD_ERROR("no \"%s\" defined for shout device defined at line " \
+ "%i\n", name, param.line);
- return ret;
+ return value;
}
-static void free_shout_data(struct shout_data *sd)
-{
- if (sd->shout_meta)
- shout_metadata_free(sd->shout_meta);
- if (sd->shout_conn)
- shout_free(sd->shout_conn);
-
- g_free(sd);
-}
-
-#define check_block_param(name) { \
- block_param = config_get_block_param(param, name); \
- if (!block_param) { \
- MPD_ERROR("no \"%s\" defined for shout device defined at line " \
- "%i\n", name, param->line); \
- } \
- }
-
-static struct audio_output *
-my_shout_init_driver(const struct config_param *param,
- GError **error)
+inline bool
+ShoutOutput::Configure(const config_param &param, GError **error_r)
{
- struct shout_data *sd = new_shout_data();
- if (!ao_base_init(&sd->base, &shout_output_plugin, param, error)) {
- free_shout_data(sd);
- return NULL;
- }
- const struct audio_format *audio_format =
- &sd->base.config_audio_format;
- if (!audio_format_fully_defined(audio_format)) {
- g_set_error(error, shout_output_quark(), 0,
+ 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");
- ao_base_finish(&sd->base);
- free_shout_data(sd);
- return NULL;
+ return nullptr;
}
- if (shout_init_count == 0)
- shout_init();
-
- shout_init_count++;
-
- const struct block_param *block_param;
- check_block_param("host");
- char *host = block_param->value;
-
- check_block_param("mount");
- char *mount = block_param->value;
-
- unsigned port = config_get_block_unsigned(param, "port", 0);
+ const char *host = require_block_string(param, "host");
+ const char *mount = require_block_string(param, "mount");
+ unsigned port = param.GetBlockValue("port", 0u);
if (port == 0) {
- g_set_error(error, shout_output_quark(), 0,
+ g_set_error(error_r, shout_output_quark(), 0,
"shout port must be configured");
- goto failure;
+ return false;
}
- check_block_param("password");
- const char *passwd = block_param->value;
+ const char *passwd = require_block_string(param, "password");
+ const char *name = require_block_string(param, "name");
- check_block_param("name");
- const char *name = block_param->value;
+ bool is_public = param.GetBlockValue("public", false);
- bool public = config_get_block_bool(param, "public", false);
+ const char *user = param.GetBlockValue("user", "source");
- const char *user = config_get_block_string(param, "user", "source");
-
- const char *value = config_get_block_string(param, "quality", NULL);
- if (value != NULL) {
+ const char *value = param.GetBlockValue("quality");
+ if (value != nullptr) {
char *test;
- sd->quality = strtod(value, &test);
+ quality = strtod(value, &test);
- if (*test != '\0' || sd->quality < -1.0 || sd->quality > 10.0) {
- g_set_error(error, shout_output_quark(), 0,
+ 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);
- goto failure;
+ value, param.line);
+ return false;
}
- if (config_get_block_string(param, "bitrate", NULL) != NULL) {
- g_set_error(error, shout_output_quark(), 0,
+ if (param.GetBlockValue("bitrate") != nullptr) {
+ g_set_error(error_r, shout_output_quark(), 0,
"quality and bitrate are "
"both defined");
- goto failure;
+ return false;
}
} else {
- value = config_get_block_string(param, "bitrate", NULL);
- if (value == NULL) {
- g_set_error(error, shout_output_quark(), 0,
+ value = param.GetBlockValue("bitrate");
+ if (value == nullptr) {
+ g_set_error(error_r, shout_output_quark(), 0,
"neither bitrate nor quality defined");
- goto failure;
+ return false;
}
char *test;
- sd->bitrate = strtol(value, &test, 10);
+ bitrate = strtol(value, &test, 10);
- if (*test != '\0' || sd->bitrate <= 0) {
- g_set_error(error, shout_output_quark(), 0,
+ if (*test != '\0' || bitrate <= 0) {
+ g_set_error(error_r, shout_output_quark(), 0,
"bitrate must be a positive integer");
- goto failure;
+ return false;
}
}
- const char *encoding = config_get_block_string(param, "encoding",
- "ogg");
- const struct encoder_plugin *encoder_plugin =
- shout_encoder_plugin_get(encoding);
- if (encoder_plugin == NULL) {
- g_set_error(error, shout_output_quark(), 0,
+ 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);
- goto failure;
+ return false;
}
- sd->encoder = encoder_init(encoder_plugin, param, error);
- if (sd->encoder == NULL)
- goto failure;
+ encoder = encoder_init(*encoder_plugin, param, error_r);
+ if (encoder == nullptr)
+ return false;
unsigned shout_format;
if (strcmp(encoding, "mp3") == 0 || strcmp(encoding, "lame") == 0)
@@ -213,14 +196,14 @@ my_shout_init_driver(const struct config_param *param,
shout_format = SHOUT_FORMAT_OGG;
unsigned protocol;
- value = config_get_block_string(param, "protocol", NULL);
- if (value != NULL) {
+ value = param.GetBlockValue("protocol");
+ if (value != nullptr) {
if (0 == strcmp(value, "shoutcast") &&
0 != strcmp(encoding, "mp3")) {
- g_set_error(error, shout_output_quark(), 0,
+ g_set_error(error_r, shout_output_quark(), 0,
"you cannot stream \"%s\" to shoutcast, use mp3",
encoding);
- goto failure;
+ return false;
} else if (0 == strcmp(value, "shoutcast"))
protocol = SHOUT_PROTOCOL_ICY;
else if (0 == strcmp(value, "icecast1"))
@@ -228,89 +211,106 @@ my_shout_init_driver(const struct config_param *param,
else if (0 == strcmp(value, "icecast2"))
protocol = SHOUT_PROTOCOL_HTTP;
else {
- g_set_error(error, shout_output_quark(), 0,
+ g_set_error(error_r, shout_output_quark(), 0,
"shout protocol \"%s\" is not \"shoutcast\" or "
"\"icecast1\"or \"icecast2\"",
value);
- goto failure;
+ return false;
}
} else {
protocol = SHOUT_PROTOCOL_HTTP;
}
- if (shout_set_host(sd->shout_conn, host) != SHOUTERR_SUCCESS ||
- shout_set_port(sd->shout_conn, port) != SHOUTERR_SUCCESS ||
- shout_set_password(sd->shout_conn, passwd) != SHOUTERR_SUCCESS ||
- shout_set_mount(sd->shout_conn, mount) != SHOUTERR_SUCCESS ||
- shout_set_name(sd->shout_conn, name) != SHOUTERR_SUCCESS ||
- shout_set_user(sd->shout_conn, user) != SHOUTERR_SUCCESS ||
- shout_set_public(sd->shout_conn, public) != SHOUTERR_SUCCESS ||
- shout_set_format(sd->shout_conn, shout_format)
+ if (shout_set_host(shout_conn, host) != SHOUTERR_SUCCESS ||
+ shout_set_port(shout_conn, port) != SHOUTERR_SUCCESS ||
+ shout_set_password(shout_conn, passwd) != SHOUTERR_SUCCESS ||
+ shout_set_mount(shout_conn, mount) != SHOUTERR_SUCCESS ||
+ shout_set_name(shout_conn, name) != SHOUTERR_SUCCESS ||
+ shout_set_user(shout_conn, user) != SHOUTERR_SUCCESS ||
+ shout_set_public(shout_conn, is_public) != SHOUTERR_SUCCESS ||
+ shout_set_format(shout_conn, shout_format)
!= SHOUTERR_SUCCESS ||
- shout_set_protocol(sd->shout_conn, protocol) != SHOUTERR_SUCCESS ||
- shout_set_agent(sd->shout_conn, "MPD") != SHOUTERR_SUCCESS) {
- g_set_error(error, shout_output_quark(), 0,
- "%s", shout_get_error(sd->shout_conn));
- goto failure;
+ 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));
+ return false;
}
/* optional paramters */
- sd->timeout = config_get_block_unsigned(param, "timeout",
- DEFAULT_CONN_TIMEOUT);
+ timeout = param.GetBlockValue("timeout", DEFAULT_CONN_TIMEOUT);
- value = config_get_block_string(param, "genre", NULL);
- if (value != NULL && shout_set_genre(sd->shout_conn, value)) {
- g_set_error(error, shout_output_quark(), 0,
- "%s", shout_get_error(sd->shout_conn));
- goto failure;
+ 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));
+ return false;
}
- value = config_get_block_string(param, "description", NULL);
- if (value != NULL && shout_set_description(sd->shout_conn, value)) {
- g_set_error(error, shout_output_quark(), 0,
- "%s", shout_get_error(sd->shout_conn));
- goto failure;
+ 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));
+ return false;
}
- value = config_get_block_string(param, "url", NULL);
- if (value != NULL && shout_set_url(sd->shout_conn, value)) {
- g_set_error(error, shout_output_quark(), 0,
- "%s", shout_get_error(sd->shout_conn));
- goto failure;
+ 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));
+ return false;
}
{
char temp[11];
memset(temp, 0, sizeof(temp));
- snprintf(temp, sizeof(temp), "%u", audio_format->channels);
- shout_set_audio_info(sd->shout_conn, SHOUT_AI_CHANNELS, temp);
+ snprintf(temp, sizeof(temp), "%u", audio_format.channels);
+ shout_set_audio_info(shout_conn, SHOUT_AI_CHANNELS, temp);
- snprintf(temp, sizeof(temp), "%u", audio_format->sample_rate);
+ snprintf(temp, sizeof(temp), "%u", audio_format.sample_rate);
- shout_set_audio_info(sd->shout_conn, SHOUT_AI_SAMPLERATE, temp);
+ shout_set_audio_info(shout_conn, SHOUT_AI_SAMPLERATE, temp);
- if (sd->quality >= -1.0) {
- snprintf(temp, sizeof(temp), "%2.2f", sd->quality);
- shout_set_audio_info(sd->shout_conn, SHOUT_AI_QUALITY,
+ if (quality >= -1.0) {
+ snprintf(temp, sizeof(temp), "%2.2f", quality);
+ shout_set_audio_info(shout_conn, SHOUT_AI_QUALITY,
temp);
} else {
- snprintf(temp, sizeof(temp), "%d", sd->bitrate);
- shout_set_audio_info(sd->shout_conn, SHOUT_AI_BITRATE,
+ snprintf(temp, sizeof(temp), "%d", bitrate);
+ shout_set_audio_info(shout_conn, SHOUT_AI_BITRATE,
temp);
}
}
- return &sd->base;
+ return true;
+}
+
+static struct audio_output *
+my_shout_init_driver(const config_param &param, GError **error_r)
+{
+ ShoutOutput *sd = new ShoutOutput();
+ if (!sd->Initialize(param, error_r)) {
+ delete sd;
+ return nullptr;
+ }
-failure:
- ao_base_finish(&sd->base);
- free_shout_data(sd);
- return NULL;
+ if (!sd->Configure(param, error_r)) {
+ sd->Deinitialize();
+ delete sd;
+ return nullptr;
+ }
+
+ if (shout_init_count == 0)
+ shout_init();
+
+ shout_init_count++;
+
+ return &sd->base;
}
static bool
-handle_shout_error(struct shout_data *sd, int err, GError **error)
+handle_shout_error(ShoutOutput *sd, int err, GError **error)
{
switch (err) {
case SHOUTERR_SUCCESS:
@@ -338,9 +338,9 @@ handle_shout_error(struct shout_data *sd, int err, GError **error)
}
static bool
-write_page(struct shout_data *sd, GError **error)
+write_page(ShoutOutput *sd, GError **error)
{
- assert(sd->encoder != NULL);
+ assert(sd->encoder != nullptr);
while (true) {
size_t nbytes = encoder_read(sd->encoder,
@@ -356,11 +356,11 @@ write_page(struct shout_data *sd, GError **error)
return true;
}
-static void close_shout_conn(struct shout_data * sd)
+static void close_shout_conn(ShoutOutput * sd)
{
- if (sd->encoder != NULL) {
- if (encoder_end(sd->encoder, NULL))
- write_page(sd, NULL);
+ if (sd->encoder != nullptr) {
+ if (encoder_end(sd->encoder, nullptr))
+ write_page(sd, nullptr);
encoder_close(sd->encoder);
}
@@ -375,12 +375,12 @@ static void close_shout_conn(struct shout_data * sd)
static void
my_shout_finish_driver(struct audio_output *ao)
{
- struct shout_data *sd = (struct shout_data *)ao;
+ ShoutOutput *sd = (ShoutOutput *)ao;
encoder_finish(sd->encoder);
- ao_base_finish(&sd->base);
- free_shout_data(sd);
+ sd->Deinitialize();
+ delete sd;
shout_init_count--;
@@ -392,7 +392,7 @@ static void
my_shout_drop_buffered_audio(struct audio_output *ao)
{
G_GNUC_UNUSED
- struct shout_data *sd = (struct shout_data *)ao;
+ ShoutOutput *sd = (ShoutOutput *)ao;
/* needs to be implemented for shout */
}
@@ -400,13 +400,13 @@ my_shout_drop_buffered_audio(struct audio_output *ao)
static void
my_shout_close_device(struct audio_output *ao)
{
- struct shout_data *sd = (struct shout_data *)ao;
+ ShoutOutput *sd = (ShoutOutput *)ao;
close_shout_conn(sd);
}
static bool
-shout_connect(struct shout_data *sd, GError **error)
+shout_connect(ShoutOutput *sd, GError **error)
{
switch (shout_open(sd->shout_conn)) {
case SHOUTERR_SUCCESS:
@@ -424,10 +424,10 @@ shout_connect(struct shout_data *sd, GError **error)
}
static bool
-my_shout_open_device(struct audio_output *ao, struct audio_format *audio_format,
+my_shout_open_device(struct audio_output *ao, AudioFormat &audio_format,
GError **error)
{
- struct shout_data *sd = (struct shout_data *)ao;
+ ShoutOutput *sd = (ShoutOutput *)ao;
if (!shout_connect(sd, error))
return false;
@@ -449,7 +449,7 @@ my_shout_open_device(struct audio_output *ao, struct audio_format *audio_format,
static unsigned
my_shout_delay(struct audio_output *ao)
{
- struct shout_data *sd = (struct shout_data *)ao;
+ ShoutOutput *sd = (ShoutOutput *)ao;
int delay = shout_delay(sd->shout_conn);
if (delay < 0)
@@ -462,7 +462,7 @@ static size_t
my_shout_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error)
{
- struct shout_data *sd = (struct shout_data *)ao;
+ ShoutOutput *sd = (ShoutOutput *)ao;
return encoder_write(sd->encoder, chunk, size, error) &&
write_page(sd, error)
@@ -473,13 +473,13 @@ my_shout_play(struct audio_output *ao, const void *chunk, size_t size,
static bool
my_shout_pause(struct audio_output *ao)
{
- static const char silence[1020];
+ static char silence[1020];
- return my_shout_play(ao, silence, sizeof(silence), NULL);
+ return my_shout_play(ao, silence, sizeof(silence), nullptr);
}
static void
-shout_tag_to_metadata(const struct tag *tag, char *dest, size_t size)
+shout_tag_to_metadata(const Tag *tag, char *dest, size_t size)
{
char artist[size];
char title[size];
@@ -505,12 +505,12 @@ shout_tag_to_metadata(const struct tag *tag, char *dest, size_t size)
}
static void my_shout_set_tag(struct audio_output *ao,
- const struct tag *tag)
+ const Tag *tag)
{
- struct shout_data *sd = (struct shout_data *)ao;
- GError *error = NULL;
+ ShoutOutput *sd = (ShoutOutput *)ao;
+ GError *error = nullptr;
- if (sd->encoder->plugin->tag != NULL) {
+ if (sd->encoder->plugin.tag != nullptr) {
/* encoder plugin supports stream tags */
if (!encoder_pre_tag(sd->encoder, &error)) {
@@ -519,7 +519,7 @@ static void my_shout_set_tag(struct audio_output *ao,
return;
}
- if (!write_page(sd, NULL))
+ if (!write_page(sd, nullptr))
return;
if (!encoder_tag(sd->encoder, tag, &error)) {
@@ -538,18 +538,23 @@ static void my_shout_set_tag(struct audio_output *ao,
}
}
- write_page(sd, NULL);
+ write_page(sd, nullptr);
}
const struct audio_output_plugin shout_output_plugin = {
- .name = "shout",
- .init = my_shout_init_driver,
- .finish = my_shout_finish_driver,
- .open = my_shout_open_device,
- .delay = my_shout_delay,
- .play = my_shout_play,
- .pause = my_shout_pause,
- .cancel = my_shout_drop_buffered_audio,
- .close = my_shout_close_device,
- .send_tag = my_shout_set_tag,
+ "shout",
+ nullptr,
+ my_shout_init_driver,
+ my_shout_finish_driver,
+ nullptr,
+ nullptr,
+ my_shout_open_device,
+ my_shout_close_device,
+ my_shout_delay,
+ my_shout_set_tag,
+ my_shout_play,
+ nullptr,
+ my_shout_drop_buffered_audio,
+ my_shout_pause,
+ nullptr,
};
diff --git a/src/output/shout_output_plugin.h b/src/output/ShoutOutputPlugin.hxx
index 9a7378803..496b77975 100644
--- a/src/output/shout_output_plugin.h
+++ b/src/output/ShoutOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_SHOUT_OUTPUT_PLUGIN_H
-#define MPD_SHOUT_OUTPUT_PLUGIN_H
+#ifndef MPD_SHOUT_OUTPUT_PLUGIN_HXX
+#define MPD_SHOUT_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin shout_output_plugin;
diff --git a/src/output/solaris_output_plugin.c b/src/output/SolarisOutputPlugin.cxx
index ce726009a..074eae728 100644
--- a/src/output/solaris_output_plugin.c
+++ b/src/output/SolarisOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,8 @@
*/
#include "config.h"
-#include "solaris_output_plugin.h"
-#include "output_api.h"
+#include "SolarisOutputPlugin.hxx"
+#include "OutputAPI.hxx"
#include "fd_util.h"
#include <glib.h>
@@ -53,13 +53,22 @@ struct audio_info {
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "solaris_output"
-struct solaris_output {
+struct SolarisOutput {
struct audio_output base;
/* configuration */
const char *device;
int fd;
+
+ bool Initialize(const config_param &param, GError **error_r) {
+ return ao_base_init(&base, &solaris_output_plugin, param,
+ error_r);
+ }
+
+ void Deinitialize() {
+ ao_base_finish(&base);
+ }
};
/**
@@ -81,16 +90,15 @@ solaris_output_test_default_device(void)
}
static struct audio_output *
-solaris_output_init(const struct config_param *param, GError **error_r)
+solaris_output_init(const config_param &param, GError **error_r)
{
- struct solaris_output *so = g_new(struct solaris_output, 1);
-
- if (!ao_base_init(&so->base, &solaris_output_plugin, param, error_r)) {
- g_free(so);
- return NULL;
+ SolarisOutput *so = new SolarisOutput();
+ if (!so->Initialize(param, error_r)) {
+ delete so;
+ return nullptr;
}
- so->device = config_get_block_string(param, "device", "/dev/audio");
+ so->device = param.GetBlockValue("device", "/dev/audio");
return &so->base;
}
@@ -98,23 +106,23 @@ solaris_output_init(const struct config_param *param, GError **error_r)
static void
solaris_output_finish(struct audio_output *ao)
{
- struct solaris_output *so = (struct solaris_output *)ao;
+ SolarisOutput *so = (SolarisOutput *)ao;
- ao_base_finish(&so->base);
- g_free(so);
+ so->Deinitialize();
+ delete so;
}
static bool
-solaris_output_open(struct audio_output *ao, struct audio_format *audio_format,
+solaris_output_open(struct audio_output *ao, AudioFormat &audio_format,
GError **error)
{
- struct solaris_output *so = (struct solaris_output *)ao;
+ SolarisOutput *so = (SolarisOutput *)ao;
struct audio_info info;
int ret, flags;
/* support only 16 bit mono/stereo for now; nothing else has
been tested */
- audio_format->format = SAMPLE_FORMAT_S16;
+ audio_format.format = SampleFormat::S16;
/* open the device in non-blocking mode */
@@ -142,8 +150,8 @@ solaris_output_open(struct audio_output *ao, struct audio_format *audio_format,
return false;
}
- info.play.sample_rate = audio_format->sample_rate;
- info.play.channels = audio_format->channels;
+ info.play.sample_rate = audio_format.sample_rate;
+ info.play.channels = audio_format.channels;
info.play.precision = 16;
info.play.encoding = AUDIO_ENCODING_LINEAR;
@@ -161,7 +169,7 @@ solaris_output_open(struct audio_output *ao, struct audio_format *audio_format,
static void
solaris_output_close(struct audio_output *ao)
{
- struct solaris_output *so = (struct solaris_output *)ao;
+ SolarisOutput *so = (SolarisOutput *)ao;
close(so->fd);
}
@@ -170,7 +178,7 @@ static size_t
solaris_output_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error)
{
- struct solaris_output *so = (struct solaris_output *)ao;
+ SolarisOutput *so = (SolarisOutput *)ao;
ssize_t nbytes;
nbytes = write(so->fd, chunk, size);
@@ -186,18 +194,25 @@ solaris_output_play(struct audio_output *ao, const void *chunk, size_t size,
static void
solaris_output_cancel(struct audio_output *ao)
{
- struct solaris_output *so = (struct solaris_output *)ao;
+ SolarisOutput *so = (SolarisOutput *)ao;
ioctl(so->fd, I_FLUSH);
}
const struct audio_output_plugin solaris_output_plugin = {
- .name = "solaris",
- .test_default_device = solaris_output_test_default_device,
- .init = solaris_output_init,
- .finish = solaris_output_finish,
- .open = solaris_output_open,
- .close = solaris_output_close,
- .play = solaris_output_play,
- .cancel = solaris_output_cancel,
+ "solaris",
+ solaris_output_test_default_device,
+ solaris_output_init,
+ solaris_output_finish,
+ nullptr,
+ nullptr,
+ solaris_output_open,
+ solaris_output_close,
+ nullptr,
+ nullptr,
+ solaris_output_play,
+ nullptr,
+ solaris_output_cancel,
+ nullptr,
+ nullptr,
};
diff --git a/src/output/solaris_output_plugin.h b/src/output/SolarisOutputPlugin.hxx
index 600aea8c2..d0fbd32c8 100644
--- a/src/output/solaris_output_plugin.h
+++ b/src/output/SolarisOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_SOLARIS_OUTPUT_PLUGIN_H
-#define MPD_SOLARIS_OUTPUT_PLUGIN_H
+#ifndef MPD_SOLARIS_OUTPUT_PLUGIN_HXX
+#define MPD_SOLARIS_OUTPUT_PLUGIN_HXX
extern const struct audio_output_plugin solaris_output_plugin;
diff --git a/src/output/winmm_output_plugin.c b/src/output/WinmmOutputPlugin.cxx
index 4d95834b9..d02b52c58 100644
--- a/src/output/winmm_output_plugin.c
+++ b/src/output/WinmmOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,26 +18,24 @@
*/
#include "config.h"
-#include "winmm_output_plugin.h"
-#include "output_api.h"
-#include "pcm_buffer.h"
-#include "mixer_list.h"
-#include "winmm_output_plugin.h"
+#include "WinmmOutputPlugin.hxx"
+#include "OutputAPI.hxx"
+#include "pcm/PcmBuffer.hxx"
+#include "MixerList.hxx"
#include <stdlib.h>
#include <string.h>
-#include <windows.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "winmm_output"
-struct winmm_buffer {
- struct pcm_buffer buffer;
+struct WinmmBuffer {
+ PcmBuffer buffer;
WAVEHDR hdr;
};
-struct winmm_output {
+struct WinmmOutput {
struct audio_output base;
UINT device_id;
@@ -49,7 +47,7 @@ struct winmm_output {
*/
HANDLE event;
- struct winmm_buffer buffers[8];
+ WinmmBuffer buffers[8];
unsigned next_buffer;
};
@@ -63,7 +61,7 @@ winmm_output_quark(void)
}
HWAVEOUT
-winmm_output_get_handle(struct winmm_output* output)
+winmm_output_get_handle(WinmmOutput *output)
{
return output->handle;
}
@@ -78,7 +76,7 @@ static bool
get_device_id(const char *device_name, UINT *device_id, GError **error_r)
{
/* if device is not specified use wave mapper */
- if (device_name == NULL) {
+ if (device_name == nullptr) {
*device_id = WAVE_MAPPER;
return true;
}
@@ -116,19 +114,19 @@ fail:
}
static struct audio_output *
-winmm_output_init(const struct config_param *param, GError **error_r)
+winmm_output_init(const config_param &param, GError **error_r)
{
- struct winmm_output *wo = g_new(struct winmm_output, 1);
+ WinmmOutput *wo = new WinmmOutput();
if (!ao_base_init(&wo->base, &winmm_output_plugin, param, error_r)) {
g_free(wo);
- return NULL;
+ return nullptr;
}
- const char *device = config_get_block_string(param, "device", NULL);
+ const char *device = param.GetBlockValue("device");
if (!get_device_id(device, &wo->device_id, error_r)) {
ao_base_finish(&wo->base);
g_free(wo);
- return NULL;
+ return nullptr;
}
return &wo->base;
@@ -137,49 +135,51 @@ winmm_output_init(const struct config_param *param, GError **error_r)
static void
winmm_output_finish(struct audio_output *ao)
{
- struct winmm_output *wo = (struct winmm_output *)ao;
+ WinmmOutput *wo = (WinmmOutput *)ao;
ao_base_finish(&wo->base);
- g_free(wo);
+ delete wo;
}
static bool
-winmm_output_open(struct audio_output *ao, struct audio_format *audio_format,
+winmm_output_open(struct audio_output *ao, AudioFormat &audio_format,
GError **error_r)
{
- struct winmm_output *wo = (struct winmm_output *)ao;
+ WinmmOutput *wo = (WinmmOutput *)ao;
- wo->event = CreateEvent(NULL, false, false, NULL);
- if (wo->event == NULL) {
+ wo->event = CreateEvent(nullptr, false, false, nullptr);
+ if (wo->event == nullptr) {
g_set_error(error_r, winmm_output_quark(), 0,
"CreateEvent() failed");
return false;
}
- switch (audio_format->format) {
- case SAMPLE_FORMAT_S8:
- case SAMPLE_FORMAT_S16:
+ switch (audio_format.format) {
+ case SampleFormat::S8:
+ case SampleFormat::S16:
break;
- case SAMPLE_FORMAT_S24_P32:
- case SAMPLE_FORMAT_S32:
- case SAMPLE_FORMAT_UNDEFINED:
+ case SampleFormat::S24_P32:
+ case SampleFormat::S32:
+ case SampleFormat::FLOAT:
+ case SampleFormat::DSD:
+ case SampleFormat::UNDEFINED:
/* we havn't tested formats other than S16 */
- audio_format->format = SAMPLE_FORMAT_S16;
+ audio_format.format = SampleFormat::S16;
break;
}
- if (audio_format->channels > 2)
+ if (audio_format.channels > 2)
/* same here: more than stereo was not tested */
- audio_format->channels = 2;
+ audio_format.channels = 2;
WAVEFORMATEX format;
format.wFormatTag = WAVE_FORMAT_PCM;
- format.nChannels = audio_format->channels;
- format.nSamplesPerSec = audio_format->sample_rate;
- format.nBlockAlign = audio_format_frame_size(audio_format);
+ format.nChannels = audio_format.channels;
+ format.nSamplesPerSec = audio_format.sample_rate;
+ format.nBlockAlign = audio_format.GetFrameSize();
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
- format.wBitsPerSample = audio_format_sample_size(audio_format) * 8;
+ format.wBitsPerSample = audio_format.GetSampleSize() * 8;
format.cbSize = 0;
MMRESULT result = waveOutOpen(&wo->handle, wo->device_id, &format,
@@ -192,7 +192,6 @@ winmm_output_open(struct audio_output *ao, struct audio_format *audio_format,
}
for (unsigned i = 0; i < G_N_ELEMENTS(wo->buffers); ++i) {
- pcm_buffer_init(&wo->buffers[i].buffer);
memset(&wo->buffers[i].hdr, 0, sizeof(wo->buffers[i].hdr));
}
@@ -204,10 +203,10 @@ winmm_output_open(struct audio_output *ao, struct audio_format *audio_format,
static void
winmm_output_close(struct audio_output *ao)
{
- struct winmm_output *wo = (struct winmm_output *)ao;
+ WinmmOutput *wo = (WinmmOutput *)ao;
for (unsigned i = 0; i < G_N_ELEMENTS(wo->buffers); ++i)
- pcm_buffer_deinit(&wo->buffers[i].buffer);
+ wo->buffers[i].buffer.Clear();
waveOutClose(wo->handle);
@@ -218,17 +217,17 @@ winmm_output_close(struct audio_output *ao)
* Copy data into a buffer, and prepare the wave header.
*/
static bool
-winmm_set_buffer(struct winmm_output *wo, struct winmm_buffer *buffer,
+winmm_set_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
const void *data, size_t size,
GError **error_r)
{
- void *dest = pcm_buffer_get(&buffer->buffer, size);
- assert(dest != NULL);
+ void *dest = buffer->buffer.Get(size);
+ assert(dest != nullptr);
memcpy(dest, data, size);
memset(&buffer->hdr, 0, sizeof(buffer->hdr));
- buffer->hdr.lpData = dest;
+ buffer->hdr.lpData = (LPSTR)dest;
buffer->hdr.dwBufferLength = size;
MMRESULT result = waveOutPrepareHeader(wo->handle, &buffer->hdr,
@@ -246,7 +245,7 @@ winmm_set_buffer(struct winmm_output *wo, struct winmm_buffer *buffer,
* Wait until the buffer is finished.
*/
static bool
-winmm_drain_buffer(struct winmm_output *wo, struct winmm_buffer *buffer,
+winmm_drain_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
GError **error_r)
{
if ((buffer->hdr.dwFlags & WHDR_DONE) == WHDR_DONE)
@@ -273,10 +272,10 @@ winmm_drain_buffer(struct winmm_output *wo, struct winmm_buffer *buffer,
static size_t
winmm_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error_r)
{
- struct winmm_output *wo = (struct winmm_output *)ao;
+ WinmmOutput *wo = (WinmmOutput *)ao;
/* get the next buffer from the ring and prepare it */
- struct winmm_buffer *buffer = &wo->buffers[wo->next_buffer];
+ WinmmBuffer *buffer = &wo->buffers[wo->next_buffer];
if (!winmm_drain_buffer(wo, buffer, error_r) ||
!winmm_set_buffer(wo, buffer, chunk, size, error_r))
return 0;
@@ -300,7 +299,7 @@ winmm_output_play(struct audio_output *ao, const void *chunk, size_t size, GErro
}
static bool
-winmm_drain_all_buffers(struct winmm_output *wo, GError **error_r)
+winmm_drain_all_buffers(WinmmOutput *wo, GError **error_r)
{
for (unsigned i = wo->next_buffer; i < G_N_ELEMENTS(wo->buffers); ++i)
if (!winmm_drain_buffer(wo, &wo->buffers[i], error_r))
@@ -314,12 +313,12 @@ winmm_drain_all_buffers(struct winmm_output *wo, GError **error_r)
}
static void
-winmm_stop(struct winmm_output *wo)
+winmm_stop(WinmmOutput *wo)
{
waveOutReset(wo->handle);
for (unsigned i = 0; i < G_N_ELEMENTS(wo->buffers); ++i) {
- struct winmm_buffer *buffer = &wo->buffers[i];
+ WinmmBuffer *buffer = &wo->buffers[i];
waveOutUnprepareHeader(wo->handle, &buffer->hdr,
sizeof(buffer->hdr));
}
@@ -328,29 +327,34 @@ winmm_stop(struct winmm_output *wo)
static void
winmm_output_drain(struct audio_output *ao)
{
- struct winmm_output *wo = (struct winmm_output *)ao;
+ WinmmOutput *wo = (WinmmOutput *)ao;
- if (!winmm_drain_all_buffers(wo, NULL))
+ if (!winmm_drain_all_buffers(wo, nullptr))
winmm_stop(wo);
}
static void
winmm_output_cancel(struct audio_output *ao)
{
- struct winmm_output *wo = (struct winmm_output *)ao;
+ WinmmOutput *wo = (WinmmOutput *)ao;
winmm_stop(wo);
}
const struct audio_output_plugin winmm_output_plugin = {
- .name = "winmm",
- .test_default_device = winmm_output_test_default_device,
- .init = winmm_output_init,
- .finish = winmm_output_finish,
- .open = winmm_output_open,
- .close = winmm_output_close,
- .play = winmm_output_play,
- .drain = winmm_output_drain,
- .cancel = winmm_output_cancel,
- .mixer_plugin = &winmm_mixer_plugin,
+ "winmm",
+ winmm_output_test_default_device,
+ winmm_output_init,
+ winmm_output_finish,
+ nullptr,
+ nullptr,
+ winmm_output_open,
+ winmm_output_close,
+ nullptr,
+ nullptr,
+ winmm_output_play,
+ winmm_output_drain,
+ winmm_output_cancel,
+ nullptr,
+ &winmm_mixer_plugin,
};
diff --git a/src/output/winmm_output_plugin.h b/src/output/WinmmOutputPlugin.hxx
index 0605530e1..e8688782e 100644
--- a/src/output/winmm_output_plugin.h
+++ b/src/output/WinmmOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,20 +17,25 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_WINMM_OUTPUT_PLUGIN_H
-#define MPD_WINMM_OUTPUT_PLUGIN_H
+#ifndef MPD_WINMM_OUTPUT_PLUGIN_HXX
+#define MPD_WINMM_OUTPUT_PLUGIN_HXX
#include "check.h"
#ifdef ENABLE_WINMM_OUTPUT
+#include "gcc.h"
+
#include <windows.h>
+#include <mmsystem.h>
-struct winmm_output;
+struct WinmmOutput;
extern const struct audio_output_plugin winmm_output_plugin;
-HWAVEOUT winmm_output_get_handle(struct winmm_output*);
+gcc_pure
+HWAVEOUT
+winmm_output_get_handle(WinmmOutput *);
#endif
diff --git a/src/output/ffado_output_plugin.c b/src/output/ffado_output_plugin.c
deleted file mode 100644
index ba239a4ad..000000000
--- a/src/output/ffado_output_plugin.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/*
- * Warning: this plugin was not tested successfully. I just couldn't
- * keep libffado2 from crashing. Use at your own risk.
- *
- * For details, see my Debian bug reports:
- *
- * http://bugs.debian.org/601657
- * http://bugs.debian.org/601659
- * http://bugs.debian.org/601663
- *
- */
-
-#include "config.h"
-#include "ffado_output_plugin.h"
-#include "output_api.h"
-#include "timer.h"
-
-#include <glib.h>
-#include <assert.h>
-
-#include <libffado/ffado.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "ffado"
-
-enum {
- MAX_STREAMS = 8,
-};
-
-struct mpd_ffado_stream {
- /** libffado's stream number */
- int number;
-
- float *buffer;
-};
-
-struct mpd_ffado_device {
- struct audio_output base;
-
- char *device_name;
- int verbose;
- unsigned period_size, nb_buffers;
-
- ffado_device_t *dev;
-
- /**
- * The current sample position inside the stream buffers. New
- * samples get appended at this position on all streams at the
- * same time. When the buffers are full
- * (buffer_position==period_size),
- * ffado_streaming_transfer_playback_buffers() gets called to
- * hand them over to libffado.
- */
- unsigned buffer_position;
-
- /**
- * The number of streams which are really used by MPD.
- */
- int num_streams;
- struct mpd_ffado_stream streams[MAX_STREAMS];
-};
-
-static inline GQuark
-ffado_output_quark(void)
-{
- return g_quark_from_static_string("ffado_output");
-}
-
-static struct audio_output *
-ffado_init(const struct config_param *param,
- GError **error_r)
-{
- g_debug("using libffado version %s, API=%d",
- ffado_get_version(), ffado_get_api_version());
-
- struct mpd_ffado_device *fd = g_new(struct mpd_ffado_device, 1);
- if (!ao_base_init(&fd->base, &ffado_output_plugin, param, error_r)) {
- g_free(fd);
- return NULL;
- }
-
- fd->device_name = config_dup_block_string(param, "device", NULL);
- fd->verbose = config_get_block_unsigned(param, "verbose", 0);
-
- fd->period_size = config_get_block_unsigned(param, "period_size",
- 1024);
- if (fd->period_size == 0 || fd->period_size > 1024 * 1024) {
- ao_base_finish(&fd->base);
- g_set_error(error_r, ffado_output_quark(), 0,
- "invalid period_size setting");
- return false;
- }
-
- fd->nb_buffers = config_get_block_unsigned(param, "nb_buffers", 3);
- if (fd->nb_buffers == 0 || fd->nb_buffers > 1024) {
- ao_base_finish(&fd->base);
- g_set_error(error_r, ffado_output_quark(), 0,
- "invalid nb_buffers setting");
- return false;
- }
-
- return &fd->base;
-}
-
-static void
-ffado_finish(struct audio_output *ao)
-{
- struct mpd_ffado_device *fd = (struct mpd_ffado_device *)ao;
-
- g_free(fd->device_name);
- ao_base_finish(&fd->base);
- g_free(fd);
-}
-
-static bool
-ffado_configure_stream(ffado_device_t *dev, struct mpd_ffado_stream *stream,
- GError **error_r)
-{
- char *buffer = (char *)stream->buffer;
- if (ffado_streaming_set_playback_stream_buffer(dev, stream->number,
- buffer) != 0) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "failed to configure stream buffer");
- return false;
- }
-
- if (ffado_streaming_playback_stream_onoff(dev, stream->number,
- 1) != 0) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "failed to disable stream");
- return false;
- }
-
- return true;
-}
-
-static bool
-ffado_configure(struct mpd_ffado_device *fd, struct audio_format *audio_format,
- GError **error_r)
-{
- assert(fd != NULL);
- assert(fd->dev != NULL);
- assert(audio_format->channels <= MAX_STREAMS);
-
- if (ffado_streaming_set_audio_datatype(fd->dev,
- ffado_audio_datatype_float) != 0) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "ffado_streaming_set_audio_datatype() failed");
- return false;
- }
-
- int num_streams = ffado_streaming_get_nb_playback_streams(fd->dev);
- if (num_streams < 0) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "ffado_streaming_get_nb_playback_streams() failed");
- return false;
- }
-
- g_debug("there are %d playback streams", num_streams);
-
- fd->num_streams = 0;
- for (int i = 0; i < num_streams; ++i) {
- char name[256];
- ffado_streaming_get_playback_stream_name(fd->dev, i, name,
- sizeof(name) - 1);
-
- ffado_streaming_stream_type type =
- ffado_streaming_get_playback_stream_type(fd->dev, i);
- if (type != ffado_stream_type_audio) {
- g_debug("stream %d name='%s': not an audio stream",
- i, name);
- continue;
- }
-
- if (fd->num_streams >= audio_format->channels) {
- g_debug("stream %d name='%s': ignoring",
- i, name);
- continue;
- }
-
- g_debug("stream %d name='%s'", i, name);
-
- struct mpd_ffado_stream *stream =
- &fd->streams[fd->num_streams++];
-
- stream->number = i;
-
- /* allocated buffer is zeroed = silence */
- stream->buffer = g_new0(float, fd->period_size);
-
- if (!ffado_configure_stream(fd->dev, stream, error_r))
- return false;
- }
-
- if (!audio_valid_channel_count(fd->num_streams)) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "invalid channel count from libffado: %u",
- audio_format->channels);
- return false;
- }
-
- g_debug("configured %d audio streams", fd->num_streams);
-
- if (ffado_streaming_prepare(fd->dev) != 0) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "ffado_streaming_prepare() failed");
- return false;
- }
-
- if (ffado_streaming_start(fd->dev) != 0) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "ffado_streaming_start() failed");
- return false;
- }
-
- audio_format->channels = fd->num_streams;
- return true;
-}
-
-static bool
-ffado_open(struct audio_output *ao, struct audio_format *audio_format,
- GError **error_r)
-{
- struct mpd_ffado_device *fd = (struct mpd_ffado_device *)ao;
-
- /* will be converted to floating point, choose best input
- format */
- audio_format->format = SAMPLE_FORMAT_S24_P32;
-
- ffado_device_info_t device_info;
- memset(&device_info, 0, sizeof(device_info));
- if (fd->device_name != NULL) {
- device_info.nb_device_spec_strings = 1;
- device_info.device_spec_strings = &fd->device_name;
- }
-
- ffado_options_t options;
- memset(&options, 0, sizeof(options));
- options.sample_rate = audio_format->sample_rate;
- options.period_size = fd->period_size;
- options.nb_buffers = fd->nb_buffers;
- options.verbose = fd->verbose;
-
- fd->dev = ffado_streaming_init(device_info, options);
- if (fd->dev == NULL) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "ffado_streaming_init() failed");
- return false;
- }
-
- if (!ffado_configure(fd, audio_format, error_r)) {
- ffado_streaming_finish(fd->dev);
-
- for (int i = 0; i < fd->num_streams; ++i) {
- struct mpd_ffado_stream *stream = &fd->streams[i];
- g_free(stream->buffer);
- }
-
- return false;
- }
-
- fd->buffer_position = 0;
-
- return true;
-}
-
-static void
-ffado_close(struct audio_output *ao)
-{
- struct mpd_ffado_device *fd = (struct mpd_ffado_device *)ao;
-
- ffado_streaming_stop(fd->dev);
- ffado_streaming_finish(fd->dev);
-
- for (int i = 0; i < fd->num_streams; ++i) {
- struct mpd_ffado_stream *stream = &fd->streams[i];
- g_free(stream->buffer);
- }
-}
-
-static size_t
-ffado_play(struct audio_output *ao, const void *chunk, size_t size,
- GError **error_r)
-{
- struct mpd_ffado_device *fd = (struct mpd_ffado_device *)ao;
-
- /* wait for prefious buffer to finish (if it was full) */
-
- if (fd->buffer_position >= fd->period_size) {
- switch (ffado_streaming_wait(fd->dev)) {
- case ffado_wait_ok:
- case ffado_wait_xrun:
- break;
-
- default:
- g_set_error(error_r, ffado_output_quark(), 0,
- "ffado_streaming_wait() failed");
- return 0;
- }
-
- fd->buffer_position = 0;
- }
-
- /* copy samples to stream buffers, non-interleaved */
-
- const int32_t *p = chunk;
- unsigned num_frames = size / sizeof(*p) / fd->num_streams;
- if (num_frames > fd->period_size - fd->buffer_position)
- num_frames = fd->period_size - fd->buffer_position;
-
- for (unsigned i = num_frames; i > 0; --i) {
- for (int stream = 0; stream < fd->num_streams; ++stream)
- fd->streams[stream].buffer[fd->buffer_position] =
- *p++ / (float)(1 << 23);
- ++fd->buffer_position;
- }
-
- /* if buffer full, transfer to device */
-
- if (fd->buffer_position >= fd->period_size &&
- /* libffado documentation says this function returns -1 on
- error, but that is a lie - it returns a boolean value,
- and "false" means error */
- !ffado_streaming_transfer_playback_buffers(fd->dev)) {
- g_set_error(error_r, ffado_output_quark(), 0,
- "ffado_streaming_transfer_playback_buffers() failed");
- return 0;
- }
-
- return num_frames * sizeof(*p) * fd->num_streams;
-}
-
-const struct audio_output_plugin ffado_output_plugin = {
- .name = "ffado",
- .init = ffado_init,
- .finish = ffado_finish,
- .open = ffado_open,
- .close = ffado_close,
- .play = ffado_play,
-};
diff --git a/src/output/ffado_output_plugin.h b/src/output/ffado_output_plugin.h
deleted file mode 100644
index 4dde01859..000000000
--- a/src/output/ffado_output_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_FFADO_OUTPUT_PLUGIN_H
-#define MPD_FFADO_OUTPUT_PLUGIN_H
-
-extern const struct audio_output_plugin ffado_output_plugin;
-
-#endif
diff --git a/src/output/httpd_client.c b/src/output/httpd_client.c
deleted file mode 100644
index 72de90457..000000000
--- a/src/output/httpd_client.c
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "httpd_client.h"
-#include "httpd_internal.h"
-#include "fifo_buffer.h"
-#include "page.h"
-#include "icy_server.h"
-#include "glib_socket.h"
-
-#include <stdbool.h>
-#include <assert.h>
-#include <string.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "httpd_output"
-
-struct httpd_client {
- /**
- * The httpd output object this client is connected to.
- */
- struct httpd_output *httpd;
-
- /**
- * The TCP socket.
- */
- GIOChannel *channel;
-
- /**
- * The GLib main loop source id for reading from the socket,
- * and to detect errors.
- */
- guint read_source_id;
-
- /**
- * The GLib main loop source id for writing to the socket. If
- * 0, then there is no event source currently (because there
- * are no queued pages).
- */
- guint write_source_id;
-
- /**
- * For buffered reading. This pointer is only valid while the
- * HTTP request is read.
- */
- struct fifo_buffer *input;
-
- /**
- * The current state of the client.
- */
- enum {
- /** reading the request line */
- REQUEST,
-
- /** reading the request headers */
- HEADERS,
-
- /** sending the HTTP response */
- RESPONSE,
- } state;
-
- /**
- * A queue of #page objects to be sent to the client.
- */
- GQueue *pages;
-
- /**
- * The #page which is currently being sent to the client.
- */
- struct page *current_page;
-
- /**
- * The amount of bytes which were already sent from
- * #current_page.
- */
- size_t current_position;
-
- /**
- * If DLNA streaming was an option.
- */
- bool dlna_streaming_requested;
-
- /* ICY */
-
- /**
- * Do we support sending Icy-Metadata to the client? This is
- * disabled if the httpd audio output uses encoder tags.
- */
- bool metadata_supported;
-
- /**
- * If we should sent icy metadata.
- */
- bool metadata_requested;
-
- /**
- * If the current metadata was already sent to the client.
- */
- bool metadata_sent;
-
- /**
- * The amount of streaming data between each metadata block
- */
- guint metaint;
-
- /**
- * The metadata as #page which is currently being sent to the client.
- */
- struct page *metadata;
-
- /*
- * The amount of bytes which were already sent from the metadata.
- */
- size_t metadata_current_position;
-
- /**
- * The amount of streaming data sent to the client
- * since the last icy information was sent.
- */
- guint metadata_fill;
-};
-
-static void
-httpd_client_unref_page(gpointer data, G_GNUC_UNUSED gpointer user_data)
-{
- struct page *page = data;
-
- page_unref(page);
-}
-
-void
-httpd_client_free(struct httpd_client *client)
-{
- assert(client != NULL);
-
- if (client->state == RESPONSE) {
- if (client->write_source_id != 0)
- g_source_remove(client->write_source_id);
-
- if (client->current_page != NULL)
- page_unref(client->current_page);
-
- g_queue_foreach(client->pages, httpd_client_unref_page, NULL);
- g_queue_free(client->pages);
- } else
- fifo_buffer_free(client->input);
-
- if (client->metadata)
- page_unref (client->metadata);
-
- g_source_remove(client->read_source_id);
- g_io_channel_unref(client->channel);
- g_free(client);
-}
-
-/**
- * Frees the client and removes it from the server's client list.
- */
-static void
-httpd_client_close(struct httpd_client *client)
-{
- assert(client != NULL);
-
- httpd_output_remove_client(client->httpd, client);
- httpd_client_free(client);
-}
-
-/**
- * Switch the client to the "RESPONSE" state.
- */
-static void
-httpd_client_begin_response(struct httpd_client *client)
-{
- assert(client != NULL);
- assert(client->state != RESPONSE);
-
- client->state = RESPONSE;
- client->write_source_id = 0;
- client->pages = g_queue_new();
- client->current_page = NULL;
-
- httpd_output_send_header(client->httpd, client);
-}
-
-/**
- * Handle a line of the HTTP request.
- */
-static bool
-httpd_client_handle_line(struct httpd_client *client, const char *line)
-{
- assert(client->state != RESPONSE);
-
- if (client->state == REQUEST) {
- if (strncmp(line, "GET /", 5) != 0) {
- /* only GET is supported */
- g_warning("malformed request line from client");
- return false;
- }
-
- line = strchr(line + 5, ' ');
- if (line == NULL || strncmp(line + 1, "HTTP/", 5) != 0) {
- /* HTTP/0.9 without request headers */
- httpd_client_begin_response(client);
- return true;
- }
-
- /* after the request line, request headers follow */
- client->state = HEADERS;
- return true;
- } else {
- if (*line == 0) {
- /* empty line: request is finished */
- httpd_client_begin_response(client);
- return true;
- }
-
- if (g_ascii_strncasecmp(line, "Icy-MetaData: 1", 15) == 0) {
- /* Send icy metadata */
- client->metadata_requested =
- client->metadata_supported;
- return true;
- }
-
- if (g_ascii_strncasecmp(line, "transferMode.dlna.org: Streaming", 32) == 0) {
- /* Send as dlna */
- client->dlna_streaming_requested = true;
- /* metadata is not supported by dlna streaming, so disable it */
- client->metadata_supported = false;
- client->metadata_requested = false;
- return true;
- }
-
- /* expect more request headers */
- return true;
- }
-}
-
-/**
- * Check if a complete line of input is present in the input buffer,
- * and duplicates it. It is removed from the input buffer. The
- * return value has to be freed with g_free().
- */
-static char *
-httpd_client_read_line(struct httpd_client *client)
-{
- assert(client != NULL);
- assert(client->state != RESPONSE);
-
- const char *p, *newline;
- size_t length;
- char *line;
-
- p = fifo_buffer_read(client->input, &length);
- if (p == NULL)
- /* empty input buffer */
- return NULL;
-
- newline = memchr(p, '\n', length);
- if (newline == NULL)
- /* incomplete line */
- return NULL;
-
- line = g_strndup(p, newline - p);
- fifo_buffer_consume(client->input, newline - p + 1);
-
- /* remove trailing whitespace (e.g. '\r') */
- return g_strchomp(line);
-}
-
-/**
- * Sends the status line and response headers to the client.
- */
-static bool
-httpd_client_send_response(struct httpd_client *client)
-{
- char buffer[1024];
- GError *error = NULL;
- GIOStatus status;
- gsize bytes_written;
-
- assert(client != NULL);
- assert(client->state == RESPONSE);
-
- if (client->dlna_streaming_requested) {
- g_snprintf(buffer, sizeof(buffer),
- "HTTP/1.1 206 OK\r\n"
- "Content-Type: %s\r\n"
- "Content-Length: 10000\r\n"
- "Content-RangeX: 0-1000000/1000000\r\n"
- "transferMode.dlna.org: Streaming\r\n"
- "Accept-Ranges: bytes\r\n"
- "Connection: close\r\n"
- "realTimeInfo.dlna.org: DLNA.ORG_TLAG=*\r\n"
- "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0\r\n"
- "\r\n",
- client->httpd->content_type);
-
- } else if (client->metadata_requested) {
- gchar *metadata_header;
-
- metadata_header = icy_server_metadata_header(
- client->httpd->name,
- client->httpd->genre,
- client->httpd->website,
- client->httpd->content_type,
- client->metaint);
-
- g_strlcpy(buffer, metadata_header, sizeof(buffer));
-
- g_free(metadata_header);
-
- } else { /* revert to a normal HTTP request */
- g_snprintf(buffer, sizeof(buffer),
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: %s\r\n"
- "Connection: close\r\n"
- "Pragma: no-cache\r\n"
- "Cache-Control: no-cache, no-store\r\n"
- "\r\n",
- client->httpd->content_type);
- }
-
- status = g_io_channel_write_chars(client->channel,
- buffer, strlen(buffer),
- &bytes_written, &error);
-
- switch (status) {
- case G_IO_STATUS_NORMAL:
- case G_IO_STATUS_AGAIN:
- return true;
-
- case G_IO_STATUS_EOF:
- /* client has disconnected */
-
- httpd_client_close(client);
- return false;
-
- case G_IO_STATUS_ERROR:
- /* I/O error */
-
- g_warning("failed to write to client: %s", error->message);
- g_error_free(error);
-
- httpd_client_close(client);
- return false;
- }
-
- /* unreachable */
- httpd_client_close(client);
- return false;
-}
-
-/**
- * Data has been received from the client and it is appended to the
- * input buffer.
- */
-static bool
-httpd_client_received(struct httpd_client *client)
-{
- assert(client != NULL);
- assert(client->state != RESPONSE);
-
- char *line;
- bool success;
-
- while ((line = httpd_client_read_line(client)) != NULL) {
- success = httpd_client_handle_line(client, line);
- g_free(line);
- if (!success) {
- assert(client->state != RESPONSE);
- return false;
- }
-
- if (client->state == RESPONSE) {
- if (!fifo_buffer_is_empty(client->input)) {
- g_warning("unexpected input from client");
- return false;
- }
-
- fifo_buffer_free(client->input);
-
- return httpd_client_send_response(client);
- }
- }
-
- return true;
-}
-
-static bool
-httpd_client_read(struct httpd_client *client)
-{
- char *p;
- size_t max_length;
- GError *error = NULL;
- GIOStatus status;
- gsize bytes_read;
-
- if (client->state == RESPONSE) {
- /* the client has already sent the request, and he
- must not send more */
- char buffer[1];
-
- status = g_io_channel_read_chars(client->channel, buffer,
- sizeof(buffer), &bytes_read,
- NULL);
- if (status == G_IO_STATUS_NORMAL)
- g_warning("unexpected input from client");
-
- return false;
- }
-
- p = fifo_buffer_write(client->input, &max_length);
- if (p == NULL) {
- g_warning("buffer overflow");
- return false;
- }
-
- status = g_io_channel_read_chars(client->channel, p, max_length,
- &bytes_read, &error);
- switch (status) {
- case G_IO_STATUS_NORMAL:
- fifo_buffer_append(client->input, bytes_read);
- return httpd_client_received(client);
-
- case G_IO_STATUS_AGAIN:
- /* try again later, after select() */
- return true;
-
- case G_IO_STATUS_EOF:
- /* peer disconnected */
- return false;
-
- case G_IO_STATUS_ERROR:
- /* I/O error */
- g_warning("failed to read from client: %s",
- error->message);
- g_error_free(error);
- return false;
- }
-
- /* unreachable */
- return false;
-}
-
-static gboolean
-httpd_client_in_event(G_GNUC_UNUSED GIOChannel *source, GIOCondition condition,
- gpointer data)
-{
- struct httpd_client *client = data;
- struct httpd_output *httpd = client->httpd;
- bool ret;
-
- g_mutex_lock(httpd->mutex);
-
- if (condition == G_IO_IN && httpd_client_read(client)) {
- ret = true;
- } else {
- httpd_client_close(client);
- ret = false;
- }
-
- g_mutex_unlock(httpd->mutex);
-
- return ret;
-}
-
-struct httpd_client *
-httpd_client_new(struct httpd_output *httpd, int fd, bool metadata_supported)
-{
- struct httpd_client *client = g_new(struct httpd_client, 1);
-
- client->httpd = httpd;
-
- client->channel = g_io_channel_new_socket(fd);
-
- /* GLib is responsible for closing the file descriptor */
- g_io_channel_set_close_on_unref(client->channel, true);
- /* NULL encoding means the stream is binary safe */
- g_io_channel_set_encoding(client->channel, NULL, NULL);
- /* we prefer to do buffering */
- g_io_channel_set_buffered(client->channel, false);
-
- client->read_source_id = g_io_add_watch(client->channel,
- G_IO_IN|G_IO_ERR|G_IO_HUP,
- httpd_client_in_event, client);
-
- client->input = fifo_buffer_new(4096);
- client->state = REQUEST;
-
- client->dlna_streaming_requested = false;
- client->metadata_supported = metadata_supported;
- client->metadata_requested = false;
- client->metadata_sent = true;
- client->metaint = 8192; /*TODO: just a std value */
- client->metadata = NULL;
- client->metadata_current_position = 0;
- client->metadata_fill = 0;
-
- return client;
-}
-
-static void
-httpd_client_add_page_size(gpointer data, gpointer user_data)
-{
- struct page *page = data;
- size_t *size = user_data;
-
- *size += page->size;
-}
-
-size_t
-httpd_client_queue_size(const struct httpd_client *client)
-{
- size_t size = 0;
-
- if (client->state != RESPONSE)
- return 0;
-
- g_queue_foreach(client->pages, httpd_client_add_page_size, &size);
- return size;
-}
-
-void
-httpd_client_cancel(struct httpd_client *client)
-{
- if (client->state != RESPONSE)
- return;
-
- g_queue_foreach(client->pages, httpd_client_unref_page, NULL);
- g_queue_clear(client->pages);
-
- if (client->write_source_id != 0 && client->current_page == NULL) {
- g_source_remove(client->write_source_id);
- client->write_source_id = 0;
- }
-}
-
-static GIOStatus
-write_page_to_channel(GIOChannel *channel,
- const struct page *page, size_t position,
- gsize *bytes_written_r, GError **error)
-{
- assert(channel != NULL);
- assert(page != NULL);
- assert(position < page->size);
-
- return g_io_channel_write_chars(channel,
- (const gchar*)page->data + position,
- page->size - position,
- bytes_written_r, error);
-}
-
-static GIOStatus
-write_n_bytes_to_channel(GIOChannel *channel, const struct page *page,
- size_t position, gint n,
- gsize *bytes_written_r, GError **error)
-{
- GIOStatus status;
-
- assert(channel != NULL);
- assert(page != NULL);
- assert(position < page->size);
-
- if (n == -1) {
- status = write_page_to_channel (channel, page, position,
- bytes_written_r, error);
- } else {
- status = g_io_channel_write_chars(channel,
- (const gchar*)page->data + position,
- n, bytes_written_r, error);
- }
-
- return status;
-}
-
-static gint
-bytes_left_till_metadata (struct httpd_client *client)
-{
- assert(client != NULL);
-
- if (client->metadata_requested &&
- client->current_page->size - client->current_position
- > client->metaint - client->metadata_fill)
- return client->metaint - client->metadata_fill;
-
- return -1;
-}
-
-static gboolean
-httpd_client_out_event(GIOChannel *source,
- G_GNUC_UNUSED GIOCondition condition, gpointer data)
-{
- struct httpd_client *client = data;
- struct httpd_output *httpd = client->httpd;
- GError *error = NULL;
- GIOStatus status;
- gsize bytes_written;
- gint bytes_to_write;
-
- g_mutex_lock(httpd->mutex);
-
- assert(condition == G_IO_OUT);
- assert(client->state == RESPONSE);
-
- if (client->write_source_id == 0) {
- /* another thread has removed the event source while
- this thread was waiting for httpd->mutex */
- g_mutex_unlock(httpd->mutex);
- return false;
- }
-
- if (client->current_page == NULL) {
- client->current_page = g_queue_pop_head(client->pages);
- client->current_position = 0;
- }
-
- bytes_to_write = bytes_left_till_metadata(client);
-
- if (bytes_to_write == 0) {
- gint metadata_to_write;
-
- metadata_to_write = client->metadata_current_position;
-
- if (!client->metadata_sent) {
- status = write_page_to_channel(source,
- client->metadata,
- metadata_to_write,
- &bytes_written, &error);
-
- client->metadata_current_position += bytes_written;
-
- if (client->metadata->size
- - client->metadata_current_position == 0) {
- client->metadata_fill = 0;
- client->metadata_current_position = 0;
- client->metadata_sent = true;
- }
- } else {
- struct page *empty_meta;
- guchar empty_data = 0;
-
- empty_meta = page_new_copy(&empty_data, 1);
-
- status = write_page_to_channel(source,
- empty_meta,
- metadata_to_write,
- &bytes_written, &error);
-
- client->metadata_current_position += bytes_written;
-
- if (empty_meta->size
- - client->metadata_current_position == 0) {
- client->metadata_fill = 0;
- client->metadata_current_position = 0;
- }
- }
-
- bytes_written = 0;
- } else {
- status = write_n_bytes_to_channel(source, client->current_page,
- client->current_position, bytes_to_write,
- &bytes_written, &error);
- }
-
- switch (status) {
- case G_IO_STATUS_NORMAL:
- client->current_position += bytes_written;
- assert(client->current_position <= client->current_page->size);
-
- if (client->metadata_requested)
- client->metadata_fill += bytes_written;
-
- if (client->current_position >= client->current_page->size) {
- page_unref(client->current_page);
- client->current_page = NULL;
-
- if (g_queue_is_empty(client->pages)) {
- /* all pages are sent: remove the
- event source */
- client->write_source_id = 0;
-
- g_mutex_unlock(httpd->mutex);
- return false;
- }
- }
-
- g_mutex_unlock(httpd->mutex);
- return true;
-
- case G_IO_STATUS_AGAIN:
- g_mutex_unlock(httpd->mutex);
- return true;
-
- case G_IO_STATUS_EOF:
- /* client has disconnected */
-
- httpd_client_close(client);
- g_mutex_unlock(httpd->mutex);
- return false;
-
- case G_IO_STATUS_ERROR:
- /* I/O error */
-
- g_warning("failed to write to client: %s", error->message);
- g_error_free(error);
-
- httpd_client_close(client);
- g_mutex_unlock(httpd->mutex);
- return false;
- }
-
- /* unreachable */
- httpd_client_close(client);
- g_mutex_unlock(httpd->mutex);
- return false;
-}
-
-void
-httpd_client_send(struct httpd_client *client, struct page *page)
-{
- if (client->state != RESPONSE)
- /* the client is still writing the HTTP request */
- return;
-
- page_ref(page);
- g_queue_push_tail(client->pages, page);
-
- if (client->write_source_id == 0)
- client->write_source_id =
- g_io_add_watch(client->channel, G_IO_OUT,
- httpd_client_out_event, client);
-}
-
-void
-httpd_client_send_metadata(struct httpd_client *client, struct page *page)
-{
- if (client->metadata) {
- page_unref(client->metadata);
- client->metadata = NULL;
- }
-
- g_return_if_fail (page);
-
- page_ref(page);
- client->metadata = page;
- client->metadata_sent = false;
-}
diff --git a/src/output/httpd_client.h b/src/output/httpd_client.h
deleted file mode 100644
index 739163f42..000000000
--- a/src/output/httpd_client.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_OUTPUT_HTTPD_CLIENT_H
-#define MPD_OUTPUT_HTTPD_CLIENT_H
-
-#include <glib.h>
-
-#include <stdbool.h>
-
-struct httpd_client;
-struct httpd_output;
-struct page;
-
-/**
- * Creates a new #httpd_client object
- *
- * @param httpd the HTTP output device
- * @param fd the socket file descriptor
- */
-struct httpd_client *
-httpd_client_new(struct httpd_output *httpd, int fd, bool metadata_supported);
-
-/**
- * Frees memory and resources allocated by the #httpd_client object.
- * This does not remove it from the #httpd_output object.
- */
-void
-httpd_client_free(struct httpd_client *client);
-
-/**
- * Returns the total size of this client's page queue.
- */
-size_t
-httpd_client_queue_size(const struct httpd_client *client);
-
-/**
- * Clears the page queue.
- */
-void
-httpd_client_cancel(struct httpd_client *client);
-
-/**
- * Appends a page to the client's queue.
- */
-void
-httpd_client_send(struct httpd_client *client, struct page *page);
-
-/**
- * Sends the passed metadata.
- */
-void
-httpd_client_send_metadata(struct httpd_client *client, struct page *page);
-
-#endif
diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c
deleted file mode 100644
index 1d730df7f..000000000
--- a/src/output/httpd_output_plugin.c
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "httpd_output_plugin.h"
-#include "httpd_internal.h"
-#include "httpd_client.h"
-#include "output_api.h"
-#include "encoder_plugin.h"
-#include "encoder_list.h"
-#include "resolver.h"
-#include "page.h"
-#include "icy_server.h"
-#include "fd_util.h"
-#include "server_socket.h"
-
-#include <assert.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-
-#ifdef HAVE_LIBWRAP
-#include <sys/socket.h> /* needed for AF_UNIX */
-#include <tcpd.h>
-#endif
-
-#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");
-}
-
-/**
- * Check whether there is at least one client.
- *
- * Caller must lock the mutex.
- */
-G_GNUC_PURE
-static bool
-httpd_output_has_clients(const struct httpd_output *httpd)
-{
- return httpd->clients != NULL;
-}
-
-/**
- * Check whether there is at least one client.
- */
-G_GNUC_PURE
-static bool
-httpd_output_lock_has_clients(const struct httpd_output *httpd)
-{
- g_mutex_lock(httpd->mutex);
- bool result = httpd_output_has_clients(httpd);
- g_mutex_unlock(httpd->mutex);
- return result;
-}
-
-static void
-httpd_listen_in_event(int fd, const struct sockaddr *address,
- size_t address_length, int uid, void *ctx);
-
-static bool
-httpd_output_bind(struct httpd_output *httpd, GError **error_r)
-{
- httpd->open = false;
-
- g_mutex_lock(httpd->mutex);
- bool success = server_socket_open(httpd->server_socket, error_r);
- g_mutex_unlock(httpd->mutex);
-
- return success;
-}
-
-static void
-httpd_output_unbind(struct httpd_output *httpd)
-{
- assert(!httpd->open);
-
- g_mutex_lock(httpd->mutex);
- server_socket_close(httpd->server_socket);
- g_mutex_unlock(httpd->mutex);
-}
-
-static struct audio_output *
-httpd_output_init(const struct config_param *param,
- GError **error)
-{
- struct httpd_output *httpd = g_new(struct httpd_output, 1);
- if (!ao_base_init(&httpd->base, &httpd_output_plugin, param, error)) {
- g_free(httpd);
- return NULL;
- }
-
- /* read configuration */
- httpd->name =
- config_get_block_string(param, "name", "Set name in config");
- httpd->genre =
- config_get_block_string(param, "genre", "Set genre in config");
- httpd->website =
- config_get_block_string(param, "website", "Set website in config");
-
- guint port = config_get_block_unsigned(param, "port", 8000);
-
- const char *encoder_name =
- config_get_block_string(param, "encoder", "vorbis");
- const struct encoder_plugin *encoder_plugin =
- encoder_plugin_get(encoder_name);
- if (encoder_plugin == NULL) {
- g_set_error(error, httpd_output_quark(), 0,
- "No such encoder: %s", encoder_name);
- ao_base_finish(&httpd->base);
- g_free(httpd);
- return NULL;
- }
-
- httpd->clients_max = config_get_block_unsigned(param,"max_clients", 0);
-
- /* set up bind_to_address */
-
- httpd->server_socket = server_socket_new(httpd_listen_in_event, httpd);
-
- const char *bind_to_address =
- config_get_block_string(param, "bind_to_address", NULL);
- bool success = bind_to_address != NULL &&
- strcmp(bind_to_address, "any") != 0
- ? server_socket_add_host(httpd->server_socket, bind_to_address,
- port, error)
- : server_socket_add_port(httpd->server_socket, port, error);
- if (!success) {
- ao_base_finish(&httpd->base);
- g_free(httpd);
- return NULL;
- }
-
- /* initialize metadata */
- httpd->metadata = NULL;
- httpd->unflushed_input = 0;
-
- /* initialize encoder */
-
- httpd->encoder = encoder_init(encoder_plugin, param, error);
- if (httpd->encoder == NULL) {
- ao_base_finish(&httpd->base);
- g_free(httpd);
- return NULL;
- }
-
- /* determine content type */
- httpd->content_type = encoder_get_mime_type(httpd->encoder);
- if (httpd->content_type == NULL) {
- httpd->content_type = "application/octet-stream";
- }
-
- httpd->mutex = g_mutex_new();
-
- return &httpd->base;
-}
-
-static void
-httpd_output_finish(struct audio_output *ao)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- if (httpd->metadata)
- page_unref(httpd->metadata);
-
- encoder_finish(httpd->encoder);
- server_socket_free(httpd->server_socket);
- g_mutex_free(httpd->mutex);
- ao_base_finish(&httpd->base);
- g_free(httpd);
-}
-
-/**
- * Creates a new #httpd_client object and adds it into the
- * httpd_output.clients linked list.
- */
-static void
-httpd_client_add(struct httpd_output *httpd, int fd)
-{
- struct httpd_client *client =
- httpd_client_new(httpd, fd,
- httpd->encoder->plugin->tag == NULL);
-
- httpd->clients = g_list_prepend(httpd->clients, client);
- httpd->clients_cnt++;
-
- /* pass metadata to client */
- if (httpd->metadata)
- httpd_client_send_metadata(client, httpd->metadata);
-}
-
-static void
-httpd_listen_in_event(int fd, const struct sockaddr *address,
- size_t address_length, G_GNUC_UNUSED int uid, void *ctx)
-{
- struct httpd_output *httpd = ctx;
-
- /* the listener socket has become readable - a client has
- connected */
-
-#ifdef HAVE_LIBWRAP
- if (address->sa_family != AF_UNIX) {
- char *hostaddr = sockaddr_to_string(address, address_length, NULL);
- const char *progname = g_get_prgname();
-
- struct request_info req;
- request_init(&req, RQ_FILE, fd, RQ_DAEMON, progname, 0);
-
- fromhost(&req);
-
- if (!hosts_access(&req)) {
- /* tcp wrappers says no */
- g_warning("libwrap refused connection (libwrap=%s) from %s",
- progname, hostaddr);
- g_free(hostaddr);
- close_socket(fd);
- g_mutex_unlock(httpd->mutex);
- return;
- }
-
- g_free(hostaddr);
- }
-#else
- (void)address;
- (void)address_length;
-#endif /* HAVE_WRAP */
-
- g_mutex_lock(httpd->mutex);
-
- if (fd >= 0) {
- /* can we allow additional client */
- if (httpd->open &&
- (httpd->clients_max == 0 ||
- httpd->clients_cnt < httpd->clients_max))
- httpd_client_add(httpd, fd);
- else
- close_socket(fd);
- } else if (fd < 0 && errno != EINTR) {
- g_warning("accept() failed: %s", g_strerror(errno));
- }
-
- g_mutex_unlock(httpd->mutex);
-}
-
-/**
- * Reads data from the encoder (as much as available) and returns it
- * as a new #page object.
- */
-static struct page *
-httpd_output_read_page(struct httpd_output *httpd)
-{
- if (httpd->unflushed_input >= 65536) {
- /* 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(httpd->encoder, NULL);
- httpd->unflushed_input = 0;
- }
-
- size_t size = 0;
- do {
- size_t nbytes = encoder_read(httpd->encoder,
- httpd->buffer + size,
- sizeof(httpd->buffer) - size);
- if (nbytes == 0)
- break;
-
- httpd->unflushed_input = 0;
-
- size += nbytes;
- } while (size < sizeof(httpd->buffer));
-
- if (size == 0)
- return NULL;
-
- return page_new_copy(httpd->buffer, size);
-}
-
-static bool
-httpd_output_encoder_open(struct httpd_output *httpd,
- struct audio_format *audio_format,
- GError **error)
-{
- if (!encoder_open(httpd->encoder, audio_format, error))
- return false;
-
- /* we have to remember the encoder header, i.e. the first
- bytes of encoder output after opening it, because it has to
- be sent to every new client */
- httpd->header = httpd_output_read_page(httpd);
-
- httpd->unflushed_input = 0;
-
- return true;
-}
-
-static bool
-httpd_output_enable(struct audio_output *ao, GError **error_r)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- return httpd_output_bind(httpd, error_r);
-}
-
-static void
-httpd_output_disable(struct audio_output *ao)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- httpd_output_unbind(httpd);
-}
-
-static bool
-httpd_output_open(struct audio_output *ao, struct audio_format *audio_format,
- GError **error)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- g_mutex_lock(httpd->mutex);
-
- /* open the encoder */
-
- if (!httpd_output_encoder_open(httpd, audio_format, error)) {
- g_mutex_unlock(httpd->mutex);
- return false;
- }
-
- /* initialize other attributes */
-
- httpd->clients = NULL;
- httpd->clients_cnt = 0;
- httpd->timer = timer_new(audio_format);
-
- httpd->open = true;
-
- g_mutex_unlock(httpd->mutex);
- return true;
-}
-
-static void
-httpd_client_delete(gpointer data, G_GNUC_UNUSED gpointer user_data)
-{
- struct httpd_client *client = data;
-
- httpd_client_free(client);
-}
-
-static void
-httpd_output_close(struct audio_output *ao)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- g_mutex_lock(httpd->mutex);
-
- httpd->open = false;
-
- timer_free(httpd->timer);
-
- g_list_foreach(httpd->clients, httpd_client_delete, NULL);
- g_list_free(httpd->clients);
-
- if (httpd->header != NULL)
- page_unref(httpd->header);
-
- encoder_close(httpd->encoder);
-
- g_mutex_unlock(httpd->mutex);
-}
-
-void
-httpd_output_remove_client(struct httpd_output *httpd,
- struct httpd_client *client)
-{
- assert(httpd != NULL);
- assert(client != NULL);
-
- httpd->clients = g_list_remove(httpd->clients, client);
- httpd->clients_cnt--;
-}
-
-void
-httpd_output_send_header(struct httpd_output *httpd,
- struct httpd_client *client)
-{
- if (httpd->header != NULL)
- httpd_client_send(client, httpd->header);
-}
-
-static unsigned
-httpd_output_delay(struct audio_output *ao)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- if (!httpd_output_lock_has_clients(httpd) && httpd->base.pause) {
- /* if there's no client and this output is paused,
- then httpd_output_pause() will not do anything, it
- will not fill the buffer and it will not update the
- timer; therefore, we reset the timer here */
- timer_reset(httpd->timer);
-
- /* some arbitrary delay that is long enough to avoid
- consuming too much CPU, and short enough to notice
- new clients quickly enough */
- return 1000;
- }
-
- return httpd->timer->started
- ? timer_delay(httpd->timer)
- : 0;
-}
-
-static void
-httpd_client_check_queue(gpointer data, G_GNUC_UNUSED gpointer user_data)
-{
- struct httpd_client *client = data;
-
- if (httpd_client_queue_size(client) > 256 * 1024) {
- g_debug("client is too slow, flushing its queue");
- httpd_client_cancel(client);
- }
-}
-
-static void
-httpd_client_send_page(gpointer data, gpointer user_data)
-{
- struct httpd_client *client = data;
- struct page *page = user_data;
-
- httpd_client_send(client, page);
-}
-
-/**
- * Broadcasts a page struct to all clients.
- */
-static void
-httpd_output_broadcast_page(struct httpd_output *httpd, struct page *page)
-{
- assert(page != NULL);
-
- g_mutex_lock(httpd->mutex);
- g_list_foreach(httpd->clients, httpd_client_send_page, page);
- g_mutex_unlock(httpd->mutex);
-}
-
-/**
- * Broadcasts data from the encoder to all clients.
- */
-static void
-httpd_output_encoder_to_clients(struct httpd_output *httpd)
-{
- struct page *page;
-
- g_mutex_lock(httpd->mutex);
- g_list_foreach(httpd->clients, httpd_client_check_queue, NULL);
- g_mutex_unlock(httpd->mutex);
-
- while ((page = httpd_output_read_page(httpd)) != NULL) {
- httpd_output_broadcast_page(httpd, page);
- page_unref(page);
- }
-}
-
-static bool
-httpd_output_encode_and_play(struct httpd_output *httpd,
- const void *chunk, size_t size, GError **error)
-{
- if (!encoder_write(httpd->encoder, chunk, size, error))
- return false;
-
- httpd->unflushed_input += size;
-
- httpd_output_encoder_to_clients(httpd);
-
- return true;
-}
-
-static size_t
-httpd_output_play(struct audio_output *ao, const void *chunk, size_t size,
- GError **error_r)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- if (httpd_output_lock_has_clients(httpd)) {
- if (!httpd_output_encode_and_play(httpd, chunk, size, error_r))
- return 0;
- }
-
- if (!httpd->timer->started)
- timer_start(httpd->timer);
- timer_add(httpd->timer, size);
-
- return size;
-}
-
-static bool
-httpd_output_pause(struct audio_output *ao)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- if (httpd_output_lock_has_clients(httpd)) {
- static const char silence[1020];
- return httpd_output_play(ao, silence, sizeof(silence),
- NULL) > 0;
- } else {
- return true;
- }
-}
-
-static void
-httpd_send_metadata(gpointer data, gpointer user_data)
-{
- struct httpd_client *client = data;
- struct page *icy_metadata = user_data;
-
- httpd_client_send_metadata(client, icy_metadata);
-}
-
-static void
-httpd_output_tag(struct audio_output *ao, const struct tag *tag)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- assert(tag != NULL);
-
- if (httpd->encoder->plugin->tag != NULL) {
- /* embed encoder tags */
-
- /* flush the current stream, and end it */
-
- encoder_pre_tag(httpd->encoder, NULL);
- httpd_output_encoder_to_clients(httpd);
-
- /* send the tag to the encoder - which starts a new
- stream now */
-
- encoder_tag(httpd->encoder, tag, NULL);
-
- /* the first page generated by the encoder will now be
- used as the new "header" page, which is sent to all
- new clients */
-
- struct page *page = httpd_output_read_page(httpd);
- if (page != NULL) {
- if (httpd->header != NULL)
- page_unref(httpd->header);
- httpd->header = page;
- httpd_output_broadcast_page(httpd, page);
- }
- } else {
- /* use Icy-Metadata */
-
- if (httpd->metadata != NULL)
- page_unref (httpd->metadata);
-
- httpd->metadata =
- icy_server_metadata_page(tag, TAG_ALBUM,
- TAG_ARTIST, TAG_TITLE,
- TAG_NUM_OF_ITEM_TYPES);
- if (httpd->metadata != NULL) {
- g_mutex_lock(httpd->mutex);
- g_list_foreach(httpd->clients,
- httpd_send_metadata, httpd->metadata);
- g_mutex_unlock(httpd->mutex);
- }
- }
-}
-
-static void
-httpd_client_cancel_callback(gpointer data, G_GNUC_UNUSED gpointer user_data)
-{
- struct httpd_client *client = data;
-
- httpd_client_cancel(client);
-}
-
-static void
-httpd_output_cancel(struct audio_output *ao)
-{
- struct httpd_output *httpd = (struct httpd_output *)ao;
-
- g_mutex_lock(httpd->mutex);
- g_list_foreach(httpd->clients, httpd_client_cancel_callback, NULL);
- g_mutex_unlock(httpd->mutex);
-}
-
-const struct audio_output_plugin httpd_output_plugin = {
- .name = "httpd",
- .init = httpd_output_init,
- .finish = httpd_output_finish,
- .enable = httpd_output_enable,
- .disable = httpd_output_disable,
- .open = httpd_output_open,
- .close = httpd_output_close,
- .delay = httpd_output_delay,
- .send_tag = httpd_output_tag,
- .play = httpd_output_play,
- .pause = httpd_output_pause,
- .cancel = httpd_output_cancel,
-};
diff --git a/src/output/mvp_output_plugin.c b/src/output/mvp_output_plugin.c
deleted file mode 100644
index 37e0f7c93..000000000
--- a/src/output/mvp_output_plugin.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/*
- * Media MVP audio output based on code from MVPMC project:
- * http://mvpmc.sourceforge.net/
- */
-
-#include "config.h"
-#include "mvp_output_plugin.h"
-#include "output_api.h"
-#include "fd_util.h"
-
-#include <glib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "mvp"
-
-typedef struct {
- unsigned long dsp_status;
- unsigned long stream_decode_type;
- unsigned long sample_rate;
- unsigned long bit_rate;
- unsigned long raw[64 / sizeof(unsigned long)];
-} aud_status_t;
-
-#define MVP_SET_AUD_STOP _IOW('a',1,int)
-#define MVP_SET_AUD_PLAY _IOW('a',2,int)
-#define MVP_SET_AUD_PAUSE _IOW('a',3,int)
-#define MVP_SET_AUD_UNPAUSE _IOW('a',4,int)
-#define MVP_SET_AUD_SRC _IOW('a',5,int)
-#define MVP_SET_AUD_MUTE _IOW('a',6,int)
-#define MVP_SET_AUD_BYPASS _IOW('a',8,int)
-#define MVP_SET_AUD_CHANNEL _IOW('a',9,int)
-#define MVP_GET_AUD_STATUS _IOR('a',10,aud_status_t)
-#define MVP_SET_AUD_VOLUME _IOW('a',13,int)
-#define MVP_GET_AUD_VOLUME _IOR('a',14,int)
-#define MVP_SET_AUD_STREAMTYPE _IOW('a',15,int)
-#define MVP_SET_AUD_FORMAT _IOW('a',16,int)
-#define MVP_GET_AUD_SYNC _IOR('a',21,pts_sync_data_t*)
-#define MVP_SET_AUD_STC _IOW('a',22,long long int *)
-#define MVP_SET_AUD_SYNC _IOW('a',23,int)
-#define MVP_SET_AUD_END_STREAM _IOW('a',25,int)
-#define MVP_SET_AUD_RESET _IOW('a',26,int)
-#define MVP_SET_AUD_DAC_CLK _IOW('a',27,int)
-#define MVP_GET_AUD_REGS _IOW('a',28,aud_ctl_regs_t*)
-
-struct mvp_data {
- struct audio_output base;
-
- struct audio_format audio_format;
- int fd;
-};
-
-static const unsigned mvp_sample_rates[][3] = {
- {9, 8000, 32000},
- {10, 11025, 44100},
- {11, 12000, 48000},
- {1, 16000, 32000},
- {2, 22050, 44100},
- {3, 24000, 48000},
- {5, 32000, 32000},
- {0, 44100, 44100},
- {7, 48000, 48000},
- {13, 64000, 32000},
- {14, 88200, 44100},
- {15, 96000, 48000}
-};
-
-/**
- * The quark used for GError.domain.
- */
-static inline GQuark
-mvp_output_quark(void)
-{
- return g_quark_from_static_string("mvp_output");
-}
-
-/**
- * Translate a sample rate to a MVP sample rate.
- *
- * @param sample_rate the sample rate in Hz
- */
-static unsigned
-mvp_find_sample_rate(unsigned sample_rate)
-{
- for (unsigned i = 0; i < G_N_ELEMENTS(mvp_sample_rates); ++i)
- if (mvp_sample_rates[i][1] == sample_rate)
- return mvp_sample_rates[i][0];
-
- return (unsigned)-1;
-}
-
-static bool
-mvp_output_test_default_device(void)
-{
- int fd;
-
- fd = open_cloexec("/dev/adec_pcm", O_WRONLY, 0);
-
- if (fd >= 0) {
- close(fd);
- return true;
- }
-
- g_warning("Error opening PCM device \"/dev/adec_pcm\": %s\n",
- g_strerror(errno));
-
- return false;
-}
-
-static struct audio_output *
-mvp_output_init(G_GNUC_UNUSED const struct config_param *param, GError **error)
-{
- struct mvp_data *md = g_new(struct mvp_data, 1);
-
- if (!ao_base_init(&md->base, &mvp_output_plugin, param, error)) {
- g_free(md);
- return NULL;
- }
-
- md->fd = -1;
-
- return &md->base;
-}
-
-static void
-mvp_output_finish(struct audio_output *ao)
-{
- struct mvp_data *md = (struct mvp_data *)ao;
- ao_base_finish(&md->base);
- g_free(md);
-}
-
-static bool
-mvp_set_pcm_params(struct mvp_data *md, struct audio_format *audio_format,
- GError **error)
-{
- unsigned mix[5];
-
- switch (audio_format->channels) {
- case 1:
- mix[0] = 1;
- break;
-
- case 2:
- mix[0] = 0;
- break;
-
- default:
- g_debug("unsupported channel count %u - falling back to stereo",
- audio_format->channels);
- audio_format->channels = 2;
- mix[0] = 0;
- break;
- }
-
- /* 0,1=24bit(24) , 2,3=16bit */
- switch (audio_format->format) {
- case SAMPLE_FORMAT_S16:
- mix[1] = 2;
- break;
-
- case SAMPLE_FORMAT_S24_P32:
- mix[1] = 0;
- break;
-
- default:
- g_debug("unsupported sample format %s - falling back to 16 bit",
- sample_format_to_string(audio_format->format));
- audio_format->format = SAMPLE_FORMAT_S16;
- mix[1] = 2;
- break;
- }
-
- mix[3] = 0; /* stream type? */
- mix[4] = G_BYTE_ORDER == G_LITTLE_ENDIAN;
-
- /*
- * if there is an exact match for the frequency, use it.
- */
- mix[2] = mvp_find_sample_rate(audio_format->sample_rate);
- if (mix[2] == (unsigned)-1) {
- g_set_error(error, mvp_output_quark(), 0,
- "Can not find suitable output frequency for %u",
- audio_format->sample_rate);
- return false;
- }
-
- if (ioctl(md->fd, MVP_SET_AUD_FORMAT, &mix) < 0) {
- g_set_error(error, mvp_output_quark(), errno,
- "Can not set audio format");
- return false;
- }
-
- if (ioctl(md->fd, MVP_SET_AUD_SYNC, 2) != 0) {
- g_set_error(error, mvp_output_quark(), errno,
- "Can not set audio sync");
- return false;
- }
-
- if (ioctl(md->fd, MVP_SET_AUD_PLAY, 0) < 0) {
- g_set_error(error, mvp_output_quark(), errno,
- "Can not set audio play mode");
- return false;
- }
-
- return true;
-}
-
-static bool
-mvp_output_open(struct audio_output *ao, struct audio_format *audio_format,
- GError **error)
-{
- struct mvp_data *md = (struct mvp_data *)ao;
- long long int stc = 0;
- int mix[5] = { 0, 2, 7, 1, 0 };
- bool success;
-
- md->fd = open_cloexec("/dev/adec_pcm", O_RDWR | O_NONBLOCK, 0);
- if (md->fd < 0) {
- g_set_error(error, mvp_output_quark(), errno,
- "Error opening /dev/adec_pcm: %s",
- g_strerror(errno));
- return false;
- }
- if (ioctl(md->fd, MVP_SET_AUD_SRC, 1) < 0) {
- g_set_error(error, mvp_output_quark(), errno,
- "Error setting audio source: %s",
- g_strerror(errno));
- return false;
- }
- if (ioctl(md->fd, MVP_SET_AUD_STREAMTYPE, 0) < 0) {
- g_set_error(error, mvp_output_quark(), errno,
- "Error setting audio streamtype: %s",
- g_strerror(errno));
- return false;
- }
- if (ioctl(md->fd, MVP_SET_AUD_FORMAT, &mix) < 0) {
- g_set_error(error, mvp_output_quark(), errno,
- "Error setting audio format: %s",
- g_strerror(errno));
- return false;
- }
- ioctl(md->fd, MVP_SET_AUD_STC, &stc);
- if (ioctl(md->fd, MVP_SET_AUD_BYPASS, 1) < 0) {
- g_set_error(error, mvp_output_quark(), errno,
- "Error setting audio streamtype: %s",
- g_strerror(errno));
- return false;
- }
-
- success = mvp_set_pcm_params(md, audio_format, error);
- if (!success)
- return false;
-
- md->audio_format = *audio_format;
- return true;
-}
-
-static void mvp_output_close(struct audio_output *ao)
-{
- struct mvp_data *md = (struct mvp_data *)ao;
- if (md->fd >= 0)
- close(md->fd);
- md->fd = -1;
-}
-
-static void mvp_output_cancel(struct audio_output *ao)
-{
- struct mvp_data *md = (struct mvp_data *)ao;
- if (md->fd >= 0) {
- ioctl(md->fd, MVP_SET_AUD_RESET, 0x11);
- close(md->fd);
- md->fd = -1;
- }
-}
-
-static size_t
-mvp_output_play(struct audio_output *ao, const void *chunk, size_t size,
- GError **error)
-{
- struct mvp_data *md = (struct mvp_data *)ao;
- ssize_t ret;
-
- /* reopen the device since it was closed by dropBufferedAudio */
- if (md->fd < 0) {
- bool success;
-
- success = mvp_output_open(ao, &md->audio_format, error);
- if (!success)
- return 0;
- }
-
- while (true) {
- ret = write(md->fd, chunk, size);
- if (ret > 0)
- return (size_t)ret;
-
- if (ret < 0) {
- if (errno == EINTR)
- continue;
-
- g_set_error(error, mvp_output_quark(), errno,
- "Failed to write: %s", g_strerror(errno));
- return 0;
- }
- }
-}
-
-const struct audio_output_plugin mvp_output_plugin = {
- .name = "mvp",
- .test_default_device = mvp_output_test_default_device,
- .init = mvp_output_init,
- .finish = mvp_output_finish,
- .open = mvp_output_open,
- .close = mvp_output_close,
- .play = mvp_output_play,
- .cancel = mvp_output_cancel,
-};
diff --git a/src/output/mvp_output_plugin.h b/src/output/mvp_output_plugin.h
deleted file mode 100644
index e403de2b7..000000000
--- a/src/output/mvp_output_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_MVP_OUTPUT_PLUGIN_H
-#define MPD_MVP_OUTPUT_PLUGIN_H
-
-extern const struct audio_output_plugin mvp_output_plugin;
-
-#endif
diff --git a/src/output/null_output_plugin.c b/src/output/null_output_plugin.c
deleted file mode 100644
index 9d7588fff..000000000
--- a/src/output/null_output_plugin.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "null_output_plugin.h"
-#include "output_api.h"
-#include "timer.h"
-
-#include <glib.h>
-
-#include <assert.h>
-
-struct null_data {
- struct audio_output base;
-
- bool sync;
-
- struct timer *timer;
-};
-
-static struct audio_output *
-null_init(const struct config_param *param, GError **error_r)
-{
- struct null_data *nd = g_new(struct null_data, 1);
-
- if (!ao_base_init(&nd->base, &null_output_plugin, param, error_r)) {
- g_free(nd);
- return NULL;
- }
-
- nd->sync = config_get_block_bool(param, "sync", true);
-
- return &nd->base;
-}
-
-static void
-null_finish(struct audio_output *ao)
-{
- struct null_data *nd = (struct null_data *)ao;
-
- ao_base_finish(&nd->base);
- g_free(nd);
-}
-
-static bool
-null_open(struct audio_output *ao, struct audio_format *audio_format,
- G_GNUC_UNUSED GError **error)
-{
- struct null_data *nd = (struct null_data *)ao;
-
- if (nd->sync)
- nd->timer = timer_new(audio_format);
-
- return true;
-}
-
-static void
-null_close(struct audio_output *ao)
-{
- struct null_data *nd = (struct null_data *)ao;
-
- if (nd->sync)
- timer_free(nd->timer);
-}
-
-static unsigned
-null_delay(struct audio_output *ao)
-{
- struct null_data *nd = (struct null_data *)ao;
-
- return nd->sync && nd->timer->started
- ? timer_delay(nd->timer)
- : 0;
-}
-
-static size_t
-null_play(struct audio_output *ao, G_GNUC_UNUSED const void *chunk, size_t size,
- G_GNUC_UNUSED GError **error)
-{
- struct null_data *nd = (struct null_data *)ao;
- struct timer *timer = nd->timer;
-
- if (!nd->sync)
- return size;
-
- if (!timer->started)
- timer_start(timer);
- timer_add(timer, size);
-
- return size;
-}
-
-static void
-null_cancel(struct audio_output *ao)
-{
- struct null_data *nd = (struct null_data *)ao;
-
- if (!nd->sync)
- return;
-
- timer_reset(nd->timer);
-}
-
-const struct audio_output_plugin null_output_plugin = {
- .name = "null",
- .init = null_init,
- .finish = null_finish,
- .open = null_open,
- .close = null_close,
- .delay = null_delay,
- .play = null_play,
- .cancel = null_cancel,
-};