Ticket #80: 0001-RoarAudio-plugin.10.patch
File 0001-RoarAudio-plugin.10.patch, 16.8 KB (added by themaister, 13 years ago) |
---|
-
Makefile.am
From 84f1df4ad9a89b3d21650e9708c6ded0dec35df5 Mon Sep 17 00:00:00 2001 From: Themaister <maister@archlinux.us> Date: Tue, 8 Feb 2011 00:17:58 +0100 Subject: [PATCH] RoarAudio plugin --- Makefile.am | 7 + configure.ac | 17 ++ src/mixer/roar_mixer_plugin.c | 137 ++++++++++++++++ src/mixer_list.h | 1 + src/output/roar_output_plugin.h | 41 +++++ src/output/roar_plugin.c | 331 +++++++++++++++++++++++++++++++++++++++ src/output_list.c | 4 + 7 files changed, 538 insertions(+), 0 deletions(-) create mode 100644 src/mixer/roar_mixer_plugin.c create mode 100644 src/output/roar_output_plugin.h create mode 100644 src/output/roar_plugin.c diff --git a/Makefile.am b/Makefile.am index d4fec31..7b41d1c 100644
a b mpd_headers = \ 142 142 src/output/httpd_client.h \ 143 143 src/output/httpd_internal.h \ 144 144 src/output/pulse_output_plugin.h \ 145 src/output/roar_output_plugin.h \ 145 146 src/output/winmm_output_plugin.h \ 146 147 src/page.h \ 147 148 src/pcm_buffer.h \ … … OUTPUT_LIBS = \ 673 674 $(LIBWRAP_LDFLAGS) \ 674 675 $(AO_LIBS) \ 675 676 $(ALSA_LIBS) \ 677 $(ROAR_LIBS) \ 676 678 $(FFADO_LIBS) \ 677 679 $(JACK_LIBS) \ 678 680 $(OPENAL_LIBS) \ … … OUTPUT_SRC += src/output/alsa_plugin.c 706 708 MIXER_SRC += src/mixer/alsa_mixer_plugin.c 707 709 endif 708 710 711 if HAVE_ROAR 712 OUTPUT_SRC += src/output/roar_plugin.c 713 MIXER_SRC += src/mixer/roar_mixer_plugin.c 714 endif 715 709 716 if ENABLE_FFADO_OUTPUT 710 717 OUTPUT_SRC += src/output/ffado_output_plugin.c 711 718 endif -
configure.ac
diff --git a/configure.ac b/configure.ac index 89b5ce3..0d07555 100644
a b AC_ARG_ENABLE(alsa, 121 121 AS_HELP_STRING([--enable-alsa], [enable ALSA support]),, 122 122 [enable_alsa=auto]) 123 123 124 AC_ARG_ENABLE(roar, 125 AS_HELP_STRING([--enable-roar], 126 [enable support for RoarAudio]),, 127 [enable_roar=auto]) 128 124 129 AC_ARG_ENABLE(ao, 125 130 AS_HELP_STRING([--enable-ao], 126 131 [enable support for libao]),, … … fi 1221 1226 1222 1227 AM_CONDITIONAL(HAVE_ALSA, test x$enable_alsa = xyes) 1223 1228 1229 dnl ----------------------------------- ROAR ---------------------------------- 1230 MPD_AUTO_PKG(roar, ROAR, [libroar >= 0.4.0], 1231 [ROAR output plugin], [libroar not found]) 1232 1233 if test x$enable_roar = xyes; then 1234 AC_DEFINE(HAVE_ROAR, 1, [Define to enable ROAR support]) 1235 fi 1236 1237 AM_CONDITIONAL(HAVE_ROAR, test x$enable_roar = xyes) 1238 1224 1239 dnl ----------------------------------- FFADO --------------------------------- 1225 1240 1226 1241 MPD_AUTO_PKG(ffado, FFADO, [libffado], … … AM_CONDITIONAL(ENABLE_WINMM_OUTPUT, test x$enable_winmm_output = xyes) 1430 1445 dnl --------------------- Post Audio Output Plugins Tests --------------------- 1431 1446 if 1432 1447 test x$enable_alsa = xno && 1448 test x$enable_roar = xno && 1433 1449 test x$enable_ao = xno && 1434 1450 test x$enable_ffado = xno && 1435 1451 test x$enable_fifo = xno && … … results(id3,[ID3]) 1566 1582 1567 1583 printf '\nPlayback support:\n\t' 1568 1584 results(alsa,ALSA) 1585 results(roar,ROAR) 1569 1586 results(ffado,FFADO) 1570 1587 results(fifo,FIFO) 1571 1588 results(recorder_output,[File Recorder]) -
new file src/mixer/roar_mixer_plugin.c
diff --git a/src/mixer/roar_mixer_plugin.c b/src/mixer/roar_mixer_plugin.c new file mode 100644 index 0000000..85a4ceb
- + 1 /* 2 * Copyright (C) 2003-2010 The Music Player Daemon Project 3 * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft 4 * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 22 #include "config.h" 23 #include "mixer_api.h" 24 #include "output_api.h" 25 #include "output/roar_output_plugin.h" 26 27 #include <glib.h> 28 29 #include <assert.h> 30 #include <sys/stat.h> 31 #include <sys/ioctl.h> 32 #include <fcntl.h> 33 #include <errno.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 37 typedef struct roar_mpd_mixer 38 { 39 /** the base mixer class */ 40 struct mixer base; 41 roar_t *self; 42 } roar_mixer_t; 43 44 /** 45 * The quark used for GError.domain. 46 */ 47 static inline GQuark 48 roar_mixer_quark(void) 49 { 50 return g_quark_from_static_string("roar_mixer"); 51 } 52 53 static struct mixer * 54 roar_mixer_init(void *ao, G_GNUC_UNUSED const struct config_param *param, 55 G_GNUC_UNUSED GError **error_r) 56 { 57 roar_mixer_t *self = g_new(roar_mixer_t, 1); 58 self->self = ao; 59 60 mixer_init(&self->base, &roar_mixer_plugin); 61 62 return &self->base; 63 } 64 65 static void 66 roar_mixer_finish(struct mixer *data) 67 { 68 roar_mixer_t *self = (roar_mixer_t *) data; 69 70 g_free(self); 71 } 72 73 static void 74 roar_mixer_close(G_GNUC_UNUSED struct mixer *data) 75 { 76 } 77 78 static bool 79 roar_mixer_open(G_GNUC_UNUSED struct mixer *data, 80 G_GNUC_UNUSED GError **error_r) 81 { 82 return true; 83 } 84 85 static int 86 roar_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r) 87 { 88 roar_mixer_t *self = (roar_mixer_t *)mixer; 89 g_mutex_lock(self->self->lock); 90 if (self->self->vss && self->self->alive) 91 { 92 float l, r; 93 int error; 94 roar_vs_volume_get(self->self->vss, &l, &r, &error); 95 g_mutex_unlock(self->self->lock); 96 return (l + r) * 50; 97 } 98 else 99 { 100 g_mutex_unlock(self->self->lock); 101 return 0; 102 } 103 } 104 105 static bool 106 roar_mixer_set_volume(struct mixer *mixer, unsigned volume, 107 G_GNUC_UNUSED GError **error_r) 108 { 109 roar_mixer_t *self = (roar_mixer_t *)mixer; 110 g_mutex_lock(self->self->lock); 111 if (self->self->vss && self->self->alive) 112 { 113 assert(volume <= 100); 114 115 int error; 116 float level = volume / 100.0; 117 118 roar_vs_volume_mono(self->self->vss, level, &error); 119 g_mutex_unlock(self->self->lock); 120 return true; 121 } 122 else 123 { 124 g_mutex_unlock(self->self->lock); 125 return false; 126 } 127 } 128 129 const struct mixer_plugin roar_mixer_plugin = { 130 .init = roar_mixer_init, 131 .finish = roar_mixer_finish, 132 .open = roar_mixer_open, 133 .close = roar_mixer_close, 134 .get_volume = roar_mixer_get_volume, 135 .set_volume = roar_mixer_set_volume, 136 .global = false, 137 }; -
src/mixer_list.h
diff --git a/src/mixer_list.h b/src/mixer_list.h index f284c2d..95ded5c 100644
a b 28 28 extern const struct mixer_plugin software_mixer_plugin; 29 29 extern const struct mixer_plugin alsa_mixer_plugin; 30 30 extern const struct mixer_plugin oss_mixer_plugin; 31 extern const struct mixer_plugin roar_mixer_plugin; 31 32 extern const struct mixer_plugin pulse_mixer_plugin; 32 33 extern const struct mixer_plugin raop_mixer_plugin; 33 34 extern const struct mixer_plugin winmm_mixer_plugin; -
new file src/output/roar_output_plugin.h
diff --git a/src/output/roar_output_plugin.h b/src/output/roar_output_plugin.h new file mode 100644 index 0000000..1db7bff
- + 1 /* 2 * Copyright (C) 2003-2010 The Music Player Daemon Project 3 * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft 4 * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 22 #ifndef __ROAR_OUTPUT_H 23 #define __ROAR_OUTPUT_H 24 25 #include <roaraudio.h> 26 #include <glib.h> 27 28 typedef struct roar 29 { 30 roar_vs_t * vss; 31 int err; 32 char *host; 33 char *name; 34 int role; 35 struct roar_connection con; 36 struct roar_audio_info info; 37 GMutex *lock; 38 volatile bool alive; 39 } roar_t; 40 41 #endif -
new file src/output/roar_plugin.c
diff --git a/src/output/roar_plugin.c b/src/output/roar_plugin.c new file mode 100644 index 0000000..7bb878f
- + 1 /* 2 * Copyright (C) 2003-2010 The Music Player Daemon Project 3 * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft 4 * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include "config.h" 22 #include "output_api.h" 23 #include "mixer_list.h" 24 #include "roar_output_plugin.h" 25 26 #include <glib.h> 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <arpa/inet.h> 30 #include <netdb.h> 31 #include <stdint.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <stdint.h> 37 38 39 #undef G_LOG_DOMAIN 40 #define G_LOG_DOMAIN "roaraudio" 41 42 static inline GQuark 43 roar_output_quark(void) 44 { 45 return g_quark_from_static_string("roar_output"); 46 } 47 48 static void 49 roar_configure(struct roar * self, const struct config_param *param) 50 { 51 self->host = config_dup_block_string(param, "server", NULL); 52 self->name = config_dup_block_string(param, "name", "MPD"); 53 char *role = config_dup_block_string(param, "role", "music"); 54 if (role != NULL) 55 { 56 self->role = roar_str2role(role); 57 g_free(role); 58 } 59 else 60 self->role = ROAR_ROLE_MUSIC; 61 } 62 63 static void * 64 roar_init(G_GNUC_UNUSED const struct audio_format *audio_format, 65 const struct config_param *param, 66 G_GNUC_UNUSED GError **error) 67 { 68 GMutex *lock = g_mutex_new(); 69 70 roar_t * self = roar_mm_calloc(1, sizeof(*self)); 71 if (self == NULL) 72 { 73 g_set_error(error, roar_output_quark(), 0, "Failed to allocate memory"); 74 return NULL; 75 } 76 77 self->lock = lock; 78 self->err = ROAR_ERROR_NONE; 79 roar_configure(self, param); 80 return self; 81 } 82 83 static void 84 roar_close(void *data) 85 { 86 roar_t * self = data; 87 g_mutex_lock(self->lock); 88 self->alive = false; 89 90 if (self->vss != NULL) 91 roar_vs_close(self->vss, ROAR_VS_TRUE, &(self->err)); 92 self->vss = NULL; 93 roar_disconnect(&(self->con)); 94 g_mutex_unlock(self->lock); 95 } 96 97 static void 98 roar_finish(void *data) 99 { 100 roar_t * self = data; 101 102 g_free(self->host); 103 g_free(self->name); 104 g_mutex_free(self->lock); 105 106 roar_mm_free(data); 107 } 108 109 static bool 110 roar_open(void *data, struct audio_format *audio_format, GError **error) 111 { 112 roar_t * self = data; 113 g_mutex_lock(self->lock); 114 115 if (roar_simple_connect(&(self->con), self->host, self->name) < 0) 116 { 117 g_set_error(error, roar_output_quark(), 0, 118 "Failed to connect to Roar server"); 119 g_mutex_unlock(self->lock); 120 return false; 121 } 122 123 self->vss = roar_vs_new_from_con(&(self->con), &(self->err)); 124 125 if (self->vss == NULL || self->err != ROAR_ERROR_NONE) 126 { 127 g_set_error(error, roar_output_quark(), 0, 128 "Failed to connect to server"); 129 g_mutex_unlock(self->lock); 130 return false; 131 } 132 133 self->info.rate = audio_format->sample_rate; 134 self->info.channels = audio_format->channels; 135 self->info.codec = ROAR_CODEC_PCM_S; 136 137 switch (audio_format->format) 138 { 139 case SAMPLE_FORMAT_S8: 140 self->info.bits = 8; 141 break; 142 case SAMPLE_FORMAT_S16: 143 self->info.bits = 16; 144 break; 145 case SAMPLE_FORMAT_S24: 146 self->info.bits = 24; 147 break; 148 case SAMPLE_FORMAT_S24_P32: 149 self->info.bits = 32; 150 audio_format->format = SAMPLE_FORMAT_S32; 151 break; 152 case SAMPLE_FORMAT_S32: 153 self->info.bits = 32; 154 break; 155 default: 156 self->info.bits = 16; 157 audio_format->format = SAMPLE_FORMAT_S16; 158 } 159 audio_format->reverse_endian = 0; 160 161 if (roar_vs_stream(self->vss, &(self->info), ROAR_DIR_PLAY, 162 &(self->err)) < 0) 163 { 164 g_set_error(error, roar_output_quark(), 0, "Failed to start stream"); 165 g_mutex_unlock(self->lock); 166 return false; 167 } 168 roar_vs_role(self->vss, self->role, &(self->err)); 169 self->alive = true; 170 171 g_mutex_unlock(self->lock); 172 return true; 173 } 174 175 static void 176 roar_cancel(void *data) 177 { 178 roar_t * self = data; 179 180 g_mutex_lock(self->lock); 181 if (self->vss != NULL) 182 { 183 roar_vs_t *vss = self->vss; 184 self->vss = NULL; 185 roar_vs_close(vss, ROAR_VS_TRUE, &(self->err)); 186 self->alive = false; 187 188 vss = roar_vs_new_from_con(&(self->con), &(self->err)); 189 if (vss) 190 { 191 roar_vs_stream(vss, &(self->info), ROAR_DIR_PLAY, &(self->err)); 192 roar_vs_role(vss, self->role, &(self->err)); 193 self->vss = vss; 194 self->alive = true; 195 } 196 } 197 g_mutex_unlock(self->lock); 198 } 199 200 static size_t 201 roar_play(void *data, const void *chunk, size_t size, GError **error) 202 { 203 struct roar * self = data; 204 ssize_t rc; 205 206 if (self->vss == NULL) 207 { 208 g_set_error(error, roar_output_quark(), 0, "Connection is invalid"); 209 return 0; 210 } 211 212 rc = roar_vs_write(self->vss, chunk, size, &(self->err)); 213 if ( rc <= 0 ) 214 { 215 g_set_error(error, roar_output_quark(), 0, "Failed to play data"); 216 return 0; 217 } 218 219 return rc; 220 } 221 222 static const char* 223 roar_tag_convert(enum tag_type type, bool *is_uuid) 224 { 225 *is_uuid = false; 226 switch (type) 227 { 228 case TAG_ARTIST: 229 case TAG_ALBUM_ARTIST: 230 return "AUTHOR"; 231 case TAG_ALBUM: 232 return "ALBUM"; 233 case TAG_TITLE: 234 return "TITLE"; 235 case TAG_TRACK: 236 return "TRACK"; 237 case TAG_NAME: 238 return "NAME"; 239 case TAG_GENRE: 240 return "GENRE"; 241 case TAG_DATE: 242 return "DATE"; 243 case TAG_PERFORMER: 244 return "PERFORMER"; 245 case TAG_COMMENT: 246 return "COMMENT"; 247 case TAG_DISC: 248 return "DISCID"; 249 case TAG_COMPOSER: 250 #ifdef ROAR_META_TYPE_COMPOSER 251 return "COMPOSER"; 252 #else 253 return "AUTHOR"; 254 #endif 255 case TAG_MUSICBRAINZ_ARTISTID: 256 case TAG_MUSICBRAINZ_ALBUMID: 257 case TAG_MUSICBRAINZ_ALBUMARTISTID: 258 case TAG_MUSICBRAINZ_TRACKID: 259 *is_uuid = true; 260 return "HASH"; 261 262 default: 263 return NULL; 264 } 265 } 266 267 static void 268 roar_send_tag(void *data, const struct tag *meta) 269 { 270 struct roar * self = data; 271 272 if (self->vss == NULL) 273 return; 274 275 g_mutex_lock(self->lock); 276 size_t cnt = 1; 277 struct roar_keyval vals[32]; 278 memset(vals, 0, sizeof(vals)); 279 char uuid_buf[32][64]; 280 281 char timebuf[16]; 282 snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", 283 meta->time / 3600, (meta->time % 3600) / 60, meta->time % 60); 284 285 vals[0].key = g_strdup("LENGTH"); 286 vals[0].value = timebuf; 287 288 for (unsigned i = 0; i < meta->num_items && cnt < 32; i++) 289 { 290 bool is_uuid = false; 291 const char *key = roar_tag_convert(meta->items[i]->type, &is_uuid); 292 if (key != NULL) 293 { 294 if (is_uuid) 295 { 296 snprintf(uuid_buf[cnt], sizeof(uuid_buf[0]), "{UUID}%s", 297 meta->items[i]->value); 298 vals[cnt].key = g_strdup(key); 299 vals[cnt].value = uuid_buf[cnt]; 300 } 301 else 302 { 303 vals[cnt].key = g_strdup(key); 304 vals[cnt].value = meta->items[i]->value; 305 } 306 cnt++; 307 } 308 } 309 310 roar_vs_meta(self->vss, vals, cnt, &(self->err)); 311 312 for (unsigned i = 0; i < 32; i++) 313 g_free(vals[i].key); 314 315 g_mutex_unlock(self->lock); 316 } 317 318 const struct audio_output_plugin roar_output_plugin = { 319 .name = "roar", 320 .init = roar_init, 321 .finish = roar_finish, 322 .open = roar_open, 323 .play = roar_play, 324 .cancel = roar_cancel, 325 .close = roar_close, 326 .send_tag = roar_send_tag, 327 328 .mixer_plugin = &roar_mixer_plugin 329 }; 330 331 -
src/output_list.c
diff --git a/src/output_list.c b/src/output_list.c index 24b089e..75d24d6 100644
a b extern const struct audio_output_plugin null_output_plugin; 26 26 extern const struct audio_output_plugin fifo_output_plugin; 27 27 extern const struct audio_output_plugin pipe_output_plugin; 28 28 extern const struct audio_output_plugin alsaPlugin; 29 extern const struct audio_output_plugin roar_output_plugin; 29 30 extern const struct audio_output_plugin ao_output_plugin; 30 31 extern const struct audio_output_plugin oss_output_plugin; 31 32 extern const struct audio_output_plugin openal_output_plugin; … … const struct audio_output_plugin *audio_output_plugins[] = { 54 55 #ifdef HAVE_ALSA 55 56 &alsaPlugin, 56 57 #endif 58 #ifdef HAVE_ROAR 59 &roar_output_plugin, 60 #endif 57 61 #ifdef HAVE_AO 58 62 &ao_output_plugin, 59 63 #endif