From e22ef6c481ab6fff3a704c515804101d9ae399a1 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 16 Jan 2013 23:29:56 +0100 Subject: output/roar: convert to C++ --- Makefile.am | 4 +- src/OutputList.cxx | 2 +- src/mixer/RoarMixerPlugin.cxx | 76 ++++++++ src/mixer/roar_mixer_plugin.c | 104 ----------- src/output/RoarOutputPlugin.cxx | 393 +++++++++++++++++++++++++++++++++++++++ src/output/RoarOutputPlugin.hxx | 33 ++++ src/output/roar_output_plugin.c | 401 ---------------------------------------- src/output/roar_output_plugin.h | 35 ---- test/read_mixer.cxx | 6 +- 9 files changed, 508 insertions(+), 546 deletions(-) create mode 100644 src/mixer/RoarMixerPlugin.cxx delete mode 100644 src/mixer/roar_mixer_plugin.c create mode 100644 src/output/RoarOutputPlugin.cxx create mode 100644 src/output/RoarOutputPlugin.hxx delete mode 100644 src/output/roar_output_plugin.c delete mode 100644 src/output/roar_output_plugin.h diff --git a/Makefile.am b/Makefile.am index 6871f208..36684f99 100644 --- a/Makefile.am +++ b/Makefile.am @@ -825,8 +825,8 @@ endif if HAVE_ROAR liboutput_plugins_a_SOURCES += \ - src/output/roar_output_plugin.c src/output/roar_output_plugin.h -libmixer_plugins_a_SOURCES += src/mixer/roar_mixer_plugin.c + src/output/RoarOutputPlugin.cxx src/output/RoarOutputPlugin.hxx +libmixer_plugins_a_SOURCES += src/mixer/RoarMixerPlugin.cxx endif if ENABLE_FFADO_OUTPUT diff --git a/src/OutputList.cxx b/src/OutputList.cxx index df064219..a9a0b3d3 100644 --- a/src/OutputList.cxx +++ b/src/OutputList.cxx @@ -34,7 +34,7 @@ #include "output/pipe_output_plugin.h" #include "output/pulse_output_plugin.h" #include "output/recorder_output_plugin.h" -#include "output/roar_output_plugin.h" +#include "output/RoarOutputPlugin.hxx" #include "output/shout_output_plugin.h" #include "output/solaris_output_plugin.h" #include "output/winmm_output_plugin.h" diff --git a/src/mixer/RoarMixerPlugin.cxx b/src/mixer/RoarMixerPlugin.cxx new file mode 100644 index 00000000..2803203b --- /dev/null +++ b/src/mixer/RoarMixerPlugin.cxx @@ -0,0 +1,76 @@ +/* + * 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 + * + * 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 "mixer_api.h" +#include "output_api.h" +#include "output/RoarOutputPlugin.hxx" + +struct RoarMixer { + /** the base mixer class */ + struct mixer base; + RoarOutput *self; + + RoarMixer(RoarOutput *_output):self(_output) { + mixer_init(&base, &roar_mixer_plugin); + } +}; + +static struct mixer * +roar_mixer_init(void *ao, gcc_unused const struct config_param *param, + gcc_unused GError **error_r) +{ + RoarMixer *self = new RoarMixer((RoarOutput *)ao); + return &self->base; +} + +static void +roar_mixer_finish(struct mixer *data) +{ + RoarMixer *self = (RoarMixer *) data; + + delete self; +} + +static int +roar_mixer_get_volume(struct mixer *mixer, gcc_unused GError **error_r) +{ + RoarMixer *self = (RoarMixer *)mixer; + return roar_output_get_volume(self->self); +} + +static bool +roar_mixer_set_volume(struct mixer *mixer, unsigned volume, + gcc_unused GError **error_r) +{ + RoarMixer *self = (RoarMixer *)mixer; + return roar_output_set_volume(self->self, volume); +} + +const struct mixer_plugin roar_mixer_plugin = { + roar_mixer_init, + roar_mixer_finish, + nullptr, + nullptr, + roar_mixer_get_volume, + roar_mixer_set_volume, + false, +}; diff --git a/src/mixer/roar_mixer_plugin.c b/src/mixer/roar_mixer_plugin.c deleted file mode 100644 index 47d3c17f..00000000 --- a/src/mixer/roar_mixer_plugin.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2003-2010 The Music Player Daemon Project - * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft - * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen - * - * 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 "mixer_api.h" -#include "output_api.h" -#include "output/roar_output_plugin.h" - -#include - -#include -#include -#include - -typedef struct roar_mpd_mixer -{ - /** the base mixer class */ - struct mixer base; - struct roar *self; -} roar_mixer_t; - -/** - * The quark used for GError.domain. - */ -static inline GQuark -roar_mixer_quark(void) -{ - return g_quark_from_static_string("roar_mixer"); -} - -static struct mixer * -roar_mixer_init(void *ao, G_GNUC_UNUSED const struct config_param *param, - G_GNUC_UNUSED GError **error_r) -{ - roar_mixer_t *self = g_new(roar_mixer_t, 1); - self->self = ao; - - mixer_init(&self->base, &roar_mixer_plugin); - - return &self->base; -} - -static void -roar_mixer_finish(struct mixer *data) -{ - roar_mixer_t *self = (roar_mixer_t *) data; - - g_free(self); -} - -static void -roar_mixer_close(G_GNUC_UNUSED struct mixer *data) -{ -} - -static bool -roar_mixer_open(G_GNUC_UNUSED struct mixer *data, - G_GNUC_UNUSED GError **error_r) -{ - return true; -} - -static int -roar_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r) -{ - roar_mixer_t *self = (roar_mixer_t *)mixer; - return roar_output_get_volume(self->self); -} - -static bool -roar_mixer_set_volume(struct mixer *mixer, unsigned volume, - G_GNUC_UNUSED GError **error_r) -{ - roar_mixer_t *self = (roar_mixer_t *)mixer; - return roar_output_set_volume(self->self, volume); -} - -const struct mixer_plugin roar_mixer_plugin = { - .init = roar_mixer_init, - .finish = roar_mixer_finish, - .open = roar_mixer_open, - .close = roar_mixer_close, - .get_volume = roar_mixer_get_volume, - .set_volume = roar_mixer_set_volume, - .global = false, -}; diff --git a/src/output/RoarOutputPlugin.cxx b/src/output/RoarOutputPlugin.cxx new file mode 100644 index 00000000..43aeb09a --- /dev/null +++ b/src/output/RoarOutputPlugin.cxx @@ -0,0 +1,393 @@ +/* + * 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 + * + * 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 "RoarOutputPlugin.hxx" +#include "output_api.h" +#include "mixer_list.h" +#include "thread/Mutex.hxx" + +#include + +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "roaraudio" + +struct RoarOutput { + struct audio_output base; + + roar_vs_t * vss; + int err; + char *host; + char *name; + int role; + struct roar_connection con; + struct roar_audio_info info; + Mutex mutex; + volatile bool alive; + + RoarOutput() + :err(ROAR_ERROR_NONE), + host(nullptr), name(nullptr) {} + + ~RoarOutput() { + g_free(host); + g_free(name); + } +}; + +static inline GQuark +roar_output_quark(void) +{ + return g_quark_from_static_string("roar_output"); +} + +static int +roar_output_get_volume_locked(RoarOutput *roar) +{ + if (roar->vss == nullptr || !roar->alive) + return -1; + + float l, r; + int error; + if (roar_vs_volume_get(roar->vss, &l, &r, &error) < 0) + return -1; + + return (l + r) * 50; +} + +int +roar_output_get_volume(RoarOutput *roar) +{ + const ScopeLock protect(roar->mutex); + return roar_output_get_volume_locked(roar); +} + +static bool +roar_output_set_volume_locked(RoarOutput *roar, unsigned volume) +{ + assert(volume <= 100); + + if (roar->vss == nullptr || !roar->alive) + return false; + + int error; + float level = volume / 100.0; + + roar_vs_volume_mono(roar->vss, level, &error); + return true; +} + +bool +roar_output_set_volume(RoarOutput *roar, unsigned volume) +{ + const ScopeLock protect(roar->mutex); + return roar_output_set_volume_locked(roar, volume); +} + +static void +roar_configure(RoarOutput *self, const struct config_param *param) +{ + self->host = config_dup_block_string(param, "server", nullptr); + self->name = config_dup_block_string(param, "name", "MPD"); + + const char *role = config_get_block_string(param, "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) +{ + RoarOutput *self = new RoarOutput(); + + if (!ao_base_init(&self->base, &roar_output_plugin, param, error_r)) { + delete self; + return nullptr; + } + + roar_configure(self, param); + return &self->base; +} + +static void +roar_finish(struct audio_output *ao) +{ + RoarOutput *self = (RoarOutput *)ao; + + ao_base_finish(&self->base); + delete self; +} + +static void +roar_use_audio_format(struct roar_audio_info *info, + struct audio_format *audio_format) +{ + 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: + info->bits = 16; + audio_format->format = SAMPLE_FORMAT_S16; + break; + + case SAMPLE_FORMAT_S8: + info->bits = 8; + break; + + case SAMPLE_FORMAT_S16: + info->bits = 16; + break; + + case SAMPLE_FORMAT_S24_P32: + info->bits = 32; + audio_format->format = SAMPLE_FORMAT_S32; + break; + + case SAMPLE_FORMAT_S32: + info->bits = 32; + break; + } +} + +static bool +roar_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) +{ + RoarOutput *self = (RoarOutput *)ao; + const ScopeLock protect(self->mutex); + + if (roar_simple_connect(&(self->con), self->host, self->name) < 0) + { + g_set_error(error, roar_output_quark(), 0, + "Failed to connect to Roar server"); + return false; + } + + self->vss = roar_vs_new_from_con(&(self->con), &(self->err)); + + if (self->vss == nullptr || self->err != ROAR_ERROR_NONE) + { + g_set_error(error, roar_output_quark(), 0, + "Failed to connect to server"); + return false; + } + + roar_use_audio_format(&self->info, audio_format); + + if (roar_vs_stream(self->vss, &(self->info), ROAR_DIR_PLAY, + &(self->err)) < 0) + { + g_set_error(error, roar_output_quark(), 0, "Failed to start stream"); + return false; + } + roar_vs_role(self->vss, self->role, &(self->err)); + self->alive = true; + + return true; +} + +static void +roar_close(struct audio_output *ao) +{ + RoarOutput *self = (RoarOutput *)ao; + const ScopeLock protect(self->mutex); + + self->alive = false; + + if (self->vss != nullptr) + roar_vs_close(self->vss, ROAR_VS_TRUE, &(self->err)); + self->vss = nullptr; + roar_disconnect(&(self->con)); +} + +static void +roar_cancel_locked(RoarOutput *self) +{ + if (self->vss == nullptr) + return; + + roar_vs_t *vss = self->vss; + 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 == nullptr) + return; + + if (roar_vs_stream(vss, &(self->info), ROAR_DIR_PLAY, + &(self->err)) < 0) { + roar_vs_close(vss, ROAR_VS_TRUE, &(self->err)); + g_warning("Failed to start stream"); + return; + } + + roar_vs_role(vss, self->role, &(self->err)); + self->vss = vss; + self->alive = true; +} + +static void +roar_cancel(struct audio_output *ao) +{ + RoarOutput *self = (RoarOutput *)ao; + + const ScopeLock protect(self->mutex); + roar_cancel_locked(self); +} + +static size_t +roar_play(struct audio_output *ao, const void *chunk, size_t size, GError **error) +{ + RoarOutput *self = (RoarOutput *)ao; + ssize_t rc; + + if (self->vss == nullptr) + { + g_set_error(error, roar_output_quark(), 0, "Connection is invalid"); + return 0; + } + + rc = roar_vs_write(self->vss, chunk, size, &(self->err)); + if ( rc <= 0 ) + { + g_set_error(error, roar_output_quark(), 0, "Failed to play data"); + return 0; + } + + return rc; +} + +static const char* +roar_tag_convert(enum tag_type type, bool *is_uuid) +{ + *is_uuid = false; + switch (type) + { + case TAG_ARTIST: + case TAG_ALBUM_ARTIST: + return "AUTHOR"; + case TAG_ALBUM: + return "ALBUM"; + case TAG_TITLE: + return "TITLE"; + case TAG_TRACK: + return "TRACK"; + case TAG_NAME: + return "NAME"; + case TAG_GENRE: + return "GENRE"; + case TAG_DATE: + return "DATE"; + case TAG_PERFORMER: + return "PERFORMER"; + case TAG_COMMENT: + return "COMMENT"; + case TAG_DISC: + return "DISCID"; + case TAG_COMPOSER: +#ifdef ROAR_META_TYPE_COMPOSER + return "COMPOSER"; +#else + return "AUTHOR"; +#endif + case TAG_MUSICBRAINZ_ARTISTID: + case TAG_MUSICBRAINZ_ALBUMID: + case TAG_MUSICBRAINZ_ALBUMARTISTID: + case TAG_MUSICBRAINZ_TRACKID: + *is_uuid = true; + return "HASH"; + + default: + return nullptr; + } +} + +static void +roar_send_tag(struct audio_output *ao, const struct tag *meta) +{ + RoarOutput *self = (RoarOutput *)ao; + + if (self->vss == nullptr) + return; + + const ScopeLock protect(self->mutex); + + size_t cnt = 1; + struct roar_keyval vals[32]; + memset(vals, 0, sizeof(vals)); + char uuid_buf[32][64]; + + char timebuf[16]; + snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", + meta->time / 3600, (meta->time % 3600) / 60, meta->time % 60); + + vals[0].key = g_strdup("LENGTH"); + vals[0].value = timebuf; + + for (unsigned i = 0; i < meta->num_items && cnt < 32; i++) + { + bool is_uuid = false; + const char *key = roar_tag_convert(meta->items[i]->type, &is_uuid); + if (key != nullptr) + { + if (is_uuid) + { + snprintf(uuid_buf[cnt], sizeof(uuid_buf[0]), "{UUID}%s", + meta->items[i]->value); + vals[cnt].key = g_strdup(key); + vals[cnt].value = uuid_buf[cnt]; + } + else + { + vals[cnt].key = g_strdup(key); + vals[cnt].value = meta->items[i]->value; + } + cnt++; + } + } + + roar_vs_meta(self->vss, vals, cnt, &(self->err)); + + for (unsigned i = 0; i < 32; i++) + g_free(vals[i].key); +} + +const struct audio_output_plugin roar_output_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/RoarOutputPlugin.hxx b/src/output/RoarOutputPlugin.hxx new file mode 100644 index 00000000..faa4b4d5 --- /dev/null +++ b/src/output/RoarOutputPlugin.hxx @@ -0,0 +1,33 @@ +/* + * 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_ROAR_OUTPUT_PLUGIN_H +#define MPD_ROAR_OUTPUT_PLUGIN_H + +struct RoarOutput; + +extern const struct audio_output_plugin roar_output_plugin; + +int +roar_output_get_volume(RoarOutput *roar); + +bool +roar_output_set_volume(RoarOutput *roar, unsigned volume); + +#endif diff --git a/src/output/roar_output_plugin.c b/src/output/roar_output_plugin.c deleted file mode 100644 index 1c2c4832..00000000 --- a/src/output/roar_output_plugin.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (C) 2003-2010 The Music Player Daemon Project - * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft - * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen - * - * 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 "roar_output_plugin.h" -#include "output_api.h" -#include "mixer_list.h" -#include "roar_output_plugin.h" - -#include -#include -#include -#include -#include -#include - -#include - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "roaraudio" - -typedef struct roar -{ - struct audio_output base; - - roar_vs_t * vss; - int err; - char *host; - char *name; - int role; - struct roar_connection con; - struct roar_audio_info info; - GMutex *lock; - volatile bool alive; -} roar_t; - -static inline GQuark -roar_output_quark(void) -{ - return g_quark_from_static_string("roar_output"); -} - -static int -roar_output_get_volume_locked(struct roar *roar) -{ - if (roar->vss == NULL || !roar->alive) - return -1; - - float l, r; - int error; - if (roar_vs_volume_get(roar->vss, &l, &r, &error) < 0) - return -1; - - return (l + r) * 50; -} - -int -roar_output_get_volume(struct roar *roar) -{ - g_mutex_lock(roar->lock); - int volume = roar_output_get_volume_locked(roar); - g_mutex_unlock(roar->lock); - return volume; -} - -static bool -roar_output_set_volume_locked(struct roar *roar, unsigned volume) -{ - assert(volume <= 100); - - if (roar->vss == NULL || !roar->alive) - return false; - - int error; - float level = volume / 100.0; - - roar_vs_volume_mono(roar->vss, level, &error); - return true; -} - -bool -roar_output_set_volume(struct roar *roar, unsigned volume) -{ - g_mutex_lock(roar->lock); - bool success = roar_output_set_volume_locked(roar, volume); - g_mutex_unlock(roar->lock); - return success; -} - -static void -roar_configure(struct roar * self, const struct config_param *param) -{ - self->host = config_dup_block_string(param, "server", NULL); - self->name = config_dup_block_string(param, "name", "MPD"); - - const char *role = config_get_block_string(param, "role", "music"); - self->role = role != NULL - ? roar_str2role(role) - : ROAR_ROLE_MUSIC; -} - -static struct audio_output * -roar_init(const struct config_param *param, GError **error_r) -{ - struct roar *self = g_new0(struct roar, 1); - - if (!ao_base_init(&self->base, &roar_output_plugin, param, error_r)) { - g_free(self); - return NULL; - } - - self->lock = g_mutex_new(); - self->err = ROAR_ERROR_NONE; - roar_configure(self, param); - return &self->base; -} - -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); - - ao_base_finish(&self->base); - g_free(self); -} - -static void -roar_use_audio_format(struct roar_audio_info *info, - struct audio_format *audio_format) -{ - 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: - info->bits = 16; - audio_format->format = SAMPLE_FORMAT_S16; - break; - - case SAMPLE_FORMAT_S8: - info->bits = 8; - break; - - case SAMPLE_FORMAT_S16: - info->bits = 16; - break; - - case SAMPLE_FORMAT_S24_P32: - info->bits = 32; - audio_format->format = SAMPLE_FORMAT_S32; - break; - - case SAMPLE_FORMAT_S32: - info->bits = 32; - break; - } -} - -static bool -roar_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) -{ - struct roar *self = (struct roar *)ao; - g_mutex_lock(self->lock); - - 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) - { - g_set_error(error, roar_output_quark(), 0, - "Failed to connect to server"); - g_mutex_unlock(self->lock); - return false; - } - - roar_use_audio_format(&self->info, audio_format); - - if (roar_vs_stream(self->vss, &(self->info), ROAR_DIR_PLAY, - &(self->err)) < 0) - { - g_set_error(error, roar_output_quark(), 0, "Failed to start stream"); - 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); - self->alive = false; - - if (self->vss != NULL) - roar_vs_close(self->vss, ROAR_VS_TRUE, &(self->err)); - self->vss = NULL; - roar_disconnect(&(self->con)); - g_mutex_unlock(self->lock); -} - -static void -roar_cancel_locked(struct roar *self) -{ - if (self->vss == NULL) - return; - - roar_vs_t *vss = self->vss; - self->vss = NULL; - 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) - return; - - if (roar_vs_stream(vss, &(self->info), ROAR_DIR_PLAY, - &(self->err)) < 0) { - roar_vs_close(vss, ROAR_VS_TRUE, &(self->err)); - g_warning("Failed to start stream"); - return; - } - - roar_vs_role(vss, self->role, &(self->err)); - self->vss = vss; - self->alive = true; -} - -static void -roar_cancel(struct audio_output *ao) -{ - struct roar *self = (struct roar *)ao; - - g_mutex_lock(self->lock); - 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; - ssize_t rc; - - if (self->vss == NULL) - { - g_set_error(error, roar_output_quark(), 0, "Connection is invalid"); - return 0; - } - - rc = roar_vs_write(self->vss, chunk, size, &(self->err)); - if ( rc <= 0 ) - { - g_set_error(error, roar_output_quark(), 0, "Failed to play data"); - return 0; - } - - return rc; -} - -static const char* -roar_tag_convert(enum tag_type type, bool *is_uuid) -{ - *is_uuid = false; - switch (type) - { - case TAG_ARTIST: - case TAG_ALBUM_ARTIST: - return "AUTHOR"; - case TAG_ALBUM: - return "ALBUM"; - case TAG_TITLE: - return "TITLE"; - case TAG_TRACK: - return "TRACK"; - case TAG_NAME: - return "NAME"; - case TAG_GENRE: - return "GENRE"; - case TAG_DATE: - return "DATE"; - case TAG_PERFORMER: - return "PERFORMER"; - case TAG_COMMENT: - return "COMMENT"; - case TAG_DISC: - return "DISCID"; - case TAG_COMPOSER: -#ifdef ROAR_META_TYPE_COMPOSER - return "COMPOSER"; -#else - return "AUTHOR"; -#endif - case TAG_MUSICBRAINZ_ARTISTID: - case TAG_MUSICBRAINZ_ALBUMID: - case TAG_MUSICBRAINZ_ALBUMARTISTID: - case TAG_MUSICBRAINZ_TRACKID: - *is_uuid = true; - return "HASH"; - - default: - return NULL; - } -} - -static void -roar_send_tag(struct audio_output *ao, const struct tag *meta) -{ - struct roar *self = (struct roar *)ao; - - if (self->vss == NULL) - return; - - g_mutex_lock(self->lock); - size_t cnt = 1; - struct roar_keyval vals[32]; - memset(vals, 0, sizeof(vals)); - char uuid_buf[32][64]; - - char timebuf[16]; - snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", - meta->time / 3600, (meta->time % 3600) / 60, meta->time % 60); - - vals[0].key = g_strdup("LENGTH"); - vals[0].value = timebuf; - - for (unsigned i = 0; i < meta->num_items && cnt < 32; i++) - { - bool is_uuid = false; - const char *key = roar_tag_convert(meta->items[i]->type, &is_uuid); - if (key != NULL) - { - if (is_uuid) - { - snprintf(uuid_buf[cnt], sizeof(uuid_buf[0]), "{UUID}%s", - meta->items[i]->value); - vals[cnt].key = g_strdup(key); - vals[cnt].value = uuid_buf[cnt]; - } - else - { - vals[cnt].key = g_strdup(key); - vals[cnt].value = meta->items[i]->value; - } - cnt++; - } - } - - roar_vs_meta(self->vss, vals, cnt, &(self->err)); - - 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 -}; diff --git a/src/output/roar_output_plugin.h b/src/output/roar_output_plugin.h deleted file mode 100644 index 78b628cc..00000000 --- a/src/output/roar_output_plugin.h +++ /dev/null @@ -1,35 +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_ROAR_OUTPUT_PLUGIN_H -#define MPD_ROAR_OUTPUT_PLUGIN_H - -#include - -struct roar; - -extern const struct audio_output_plugin roar_output_plugin; - -int -roar_output_get_volume(struct roar *roar); - -bool -roar_output_set_volume(struct roar *roar, unsigned volume); - -#endif diff --git a/test/read_mixer.cxx b/test/read_mixer.cxx index c7a5a3e0..799bbefd 100644 --- a/test/read_mixer.cxx +++ b/test/read_mixer.cxx @@ -74,16 +74,16 @@ pulse_output_set_volume(G_GNUC_UNUSED struct pulse_output *po, #endif #ifdef HAVE_ROAR -#include "output/roar_output_plugin.h" +#include "output/RoarOutputPlugin.hxx" int -roar_output_get_volume(G_GNUC_UNUSED struct roar *roar) +roar_output_get_volume(gcc_unused RoarOutput *roar) { return -1; } bool -roar_output_set_volume(G_GNUC_UNUSED struct roar *roar, +roar_output_set_volume(gcc_unused RoarOutput *roar, G_GNUC_UNUSED unsigned volume) { return true; -- cgit v1.2.3