Ticket #80: 0001-RoarAudio-plugin.9.patch

File 0001-RoarAudio-plugin.9.patch, 16.8 KB (added by themaister, 13 years ago)

Small fixes.

  • Makefile.am

    From 6637787374bfd5a2bce1c6ec586c504081325aa7 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   |  135 ++++++++++++++++
     src/mixer_list.h                |    1 +
     src/output/roar_output_plugin.h |   41 +++++
     src/output/roar_plugin.c        |  330 +++++++++++++++++++++++++++++++++++++++
     src/output_list.c               |    4 +
     7 files changed, 535 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 = \ 
    142142        src/output/httpd_client.h \ 
    143143        src/output/httpd_internal.h \ 
    144144        src/output/pulse_output_plugin.h \ 
     145        src/output/roar_output_plugin.h \ 
    145146        src/output/winmm_output_plugin.h \ 
    146147        src/page.h \ 
    147148        src/pcm_buffer.h \ 
    OUTPUT_LIBS = \ 
    673674        $(LIBWRAP_LDFLAGS) \ 
    674675        $(AO_LIBS) \ 
    675676        $(ALSA_LIBS) \ 
     677        $(ROAR_LIBS) \ 
    676678        $(FFADO_LIBS) \ 
    677679        $(JACK_LIBS) \ 
    678680        $(OPENAL_LIBS) \ 
    OUTPUT_SRC += src/output/alsa_plugin.c 
    706708MIXER_SRC += src/mixer/alsa_mixer_plugin.c 
    707709endif 
    708710 
     711if HAVE_ROAR 
     712OUTPUT_SRC += src/output/roar_plugin.c 
     713MIXER_SRC += src/mixer/roar_mixer_plugin.c 
     714endif 
     715 
    709716if ENABLE_FFADO_OUTPUT 
    710717OUTPUT_SRC += src/output/ffado_output_plugin.c 
    711718endif 
  • configure.ac

    diff --git a/configure.ac b/configure.ac
    index 89b5ce3..0d07555 100644
    a b AC_ARG_ENABLE(alsa, 
    121121        AS_HELP_STRING([--enable-alsa], [enable ALSA support]),, 
    122122        [enable_alsa=auto]) 
    123123 
     124AC_ARG_ENABLE(roar, 
     125        AS_HELP_STRING([--enable-roar], 
     126                [enable support for RoarAudio]),, 
     127        [enable_roar=auto]) 
     128 
    124129AC_ARG_ENABLE(ao, 
    125130        AS_HELP_STRING([--enable-ao], 
    126131                [enable support for libao]),, 
    fi 
    12211226 
    12221227AM_CONDITIONAL(HAVE_ALSA, test x$enable_alsa = xyes) 
    12231228 
     1229dnl ----------------------------------- ROAR ---------------------------------- 
     1230MPD_AUTO_PKG(roar, ROAR, [libroar >= 0.4.0], 
     1231        [ROAR output plugin], [libroar not found]) 
     1232 
     1233if test x$enable_roar = xyes; then 
     1234        AC_DEFINE(HAVE_ROAR, 1, [Define to enable ROAR support]) 
     1235fi 
     1236 
     1237AM_CONDITIONAL(HAVE_ROAR, test x$enable_roar = xyes) 
     1238 
    12241239dnl ----------------------------------- FFADO --------------------------------- 
    12251240 
    12261241MPD_AUTO_PKG(ffado, FFADO, [libffado], 
    AM_CONDITIONAL(ENABLE_WINMM_OUTPUT, test x$enable_winmm_output = xyes) 
    14301445dnl --------------------- Post Audio Output Plugins Tests --------------------- 
    14311446if 
    14321447        test x$enable_alsa = xno && 
     1448        test x$enable_roar = xno && 
    14331449        test x$enable_ao = xno && 
    14341450        test x$enable_ffado = xno && 
    14351451        test x$enable_fifo = xno && 
    results(id3,[ID3]) 
    15661582 
    15671583printf '\nPlayback support:\n\t' 
    15681584results(alsa,ALSA) 
     1585results(roar,ROAR) 
    15691586results(ffado,FFADO) 
    15701587results(fifo,FIFO) 
    15711588results(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..6293944
    - +  
     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 
     37typedef 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 */ 
     47static inline GQuark 
     48roar_mixer_quark(void) 
     49{ 
     50        return g_quark_from_static_string("roar_mixer"); 
     51} 
     52 
     53static struct mixer * 
     54roar_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 
     65static void 
     66roar_mixer_finish(struct mixer *data) 
     67{ 
     68        roar_mixer_t *self = (roar_mixer_t *) data; 
     69 
     70        g_free(self); 
     71} 
     72 
     73static void 
     74roar_mixer_close(G_GNUC_UNUSED struct mixer *data) 
     75{ 
     76} 
     77 
     78static bool 
     79roar_mixer_open(G_GNUC_UNUSED struct mixer *data, G_GNUC_UNUSED GError **error_r) 
     80{ 
     81        return true; 
     82} 
     83 
     84static int 
     85roar_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r) 
     86{ 
     87        roar_mixer_t *self = (roar_mixer_t *)mixer; 
     88        g_mutex_lock(self->self->lock); 
     89        if (self->self->vss && self->self->alive) 
     90        { 
     91                float l, r; 
     92                int error; 
     93                roar_vs_volume_get(self->self->vss, &l, &r, &error); 
     94                g_mutex_unlock(self->self->lock); 
     95                return (l + r) * 50; 
     96        } 
     97        else 
     98        { 
     99                g_mutex_unlock(self->self->lock); 
     100                return 0; 
     101        } 
     102} 
     103 
     104static bool 
     105roar_mixer_set_volume(struct mixer *mixer, unsigned volume, G_GNUC_UNUSED GError **error_r) 
     106{ 
     107        roar_mixer_t *self = (roar_mixer_t *)mixer; 
     108        g_mutex_lock(self->self->lock); 
     109        if (self->self->vss && self->self->alive) 
     110        { 
     111                assert(volume <= 100); 
     112 
     113                int error; 
     114                float level = volume / 100.0; 
     115 
     116                roar_vs_volume_mono(self->self->vss, level, &error); 
     117                g_mutex_unlock(self->self->lock); 
     118                return true; 
     119        } 
     120        else 
     121        { 
     122                g_mutex_unlock(self->self->lock); 
     123                return false; 
     124        } 
     125} 
     126 
     127const struct mixer_plugin roar_mixer_plugin = { 
     128        .init = roar_mixer_init, 
     129        .finish = roar_mixer_finish, 
     130        .open = roar_mixer_open, 
     131        .close = roar_mixer_close, 
     132        .get_volume = roar_mixer_get_volume, 
     133        .set_volume = roar_mixer_set_volume, 
     134        .global = false, 
     135}; 
  • src/mixer_list.h

    diff --git a/src/mixer_list.h b/src/mixer_list.h
    index f284c2d..95ded5c 100644
    a b  
    2828extern const struct mixer_plugin software_mixer_plugin; 
    2929extern const struct mixer_plugin alsa_mixer_plugin; 
    3030extern const struct mixer_plugin oss_mixer_plugin; 
     31extern const struct mixer_plugin roar_mixer_plugin; 
    3132extern const struct mixer_plugin pulse_mixer_plugin; 
    3233extern const struct mixer_plugin raop_mixer_plugin; 
    3334extern 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 
     28typedef 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..e2b4d9f
    - +  
     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 
     42static inline GQuark 
     43roar_output_quark(void) 
     44{ 
     45        return g_quark_from_static_string("roar_output"); 
     46} 
     47 
     48static void 
     49roar_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 
     63static void * 
     64roar_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 
     83static void 
     84roar_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 
     97static void 
     98roar_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 
     109static bool 
     110roar_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, &(self->err)) < 0) 
     162        { 
     163                g_set_error(error, roar_output_quark(), 0, "Failed to start stream"); 
     164                g_mutex_unlock(self->lock); 
     165                return false; 
     166        } 
     167        roar_vs_role(self->vss, self->role, &(self->err)); 
     168        self->alive = true; 
     169 
     170        g_mutex_unlock(self->lock); 
     171        return true; 
     172} 
     173 
     174static void 
     175roar_cancel(void *data) 
     176{ 
     177        roar_t * self = data; 
     178 
     179        g_mutex_lock(self->lock); 
     180        if (self->vss != NULL) 
     181        { 
     182                roar_vs_t *vss = self->vss; 
     183                self->vss = NULL; 
     184                roar_vs_close(vss, ROAR_VS_TRUE, &(self->err)); 
     185                self->alive = false; 
     186 
     187                vss = roar_vs_new_from_con(&(self->con), &(self->err)); 
     188                if (vss) 
     189                { 
     190                        roar_vs_stream(vss, &(self->info), ROAR_DIR_PLAY, &(self->err)); 
     191                        roar_vs_role(vss, self->role, &(self->err)); 
     192                        self->vss = vss; 
     193                        self->alive = true; 
     194                } 
     195        } 
     196        g_mutex_unlock(self->lock); 
     197} 
     198 
     199static size_t 
     200roar_play(void *data, const void *chunk, size_t size, GError **error) 
     201{ 
     202        struct roar * self = data; 
     203        ssize_t rc; 
     204 
     205        if (self->vss == NULL) 
     206        { 
     207                g_set_error(error, roar_output_quark(), 0, "Connection is invalid"); 
     208                return 0; 
     209        } 
     210 
     211        rc = roar_vs_write(self->vss, chunk, size, &(self->err)); 
     212        if ( rc <= 0 ) 
     213        { 
     214                g_set_error(error, roar_output_quark(), 0, "Failed to play data"); 
     215                return 0; 
     216        } 
     217 
     218        return rc; 
     219} 
     220 
     221static const char* 
     222roar_tag_convert(enum tag_type type, bool *is_uuid) 
     223{ 
     224        *is_uuid = false; 
     225        switch (type) 
     226        { 
     227                case TAG_ARTIST: 
     228                case TAG_ALBUM_ARTIST: 
     229                        return "AUTHOR"; 
     230                case TAG_ALBUM: 
     231                        return "ALBUM"; 
     232                case TAG_TITLE: 
     233                        return "TITLE"; 
     234                case TAG_TRACK: 
     235                        return "TRACK"; 
     236                case TAG_NAME: 
     237                        return "NAME"; 
     238                case TAG_GENRE: 
     239                        return "GENRE"; 
     240                case TAG_DATE: 
     241                        return "DATE"; 
     242                case TAG_PERFORMER: 
     243                        return "PERFORMER"; 
     244                case TAG_COMMENT: 
     245                        return "COMMENT"; 
     246                case TAG_DISC: 
     247                        return "DISCID"; 
     248                case TAG_COMPOSER: 
     249#ifdef ROAR_META_TYPE_COMPOSER 
     250                        return "COMPOSER"; 
     251#else 
     252                        return "AUTHOR"; 
     253#endif 
     254                case TAG_MUSICBRAINZ_ARTISTID: 
     255                case TAG_MUSICBRAINZ_ALBUMID: 
     256                case TAG_MUSICBRAINZ_ALBUMARTISTID: 
     257                case TAG_MUSICBRAINZ_TRACKID: 
     258                        *is_uuid = true; 
     259                        return "HASH"; 
     260 
     261                default: 
     262                        return NULL; 
     263        } 
     264} 
     265 
     266static void 
     267roar_send_tag(void *data, const struct tag *meta) 
     268{ 
     269        struct roar * self = data; 
     270 
     271        if (self->vss == NULL) 
     272                return; 
     273 
     274        g_mutex_lock(self->lock); 
     275        size_t cnt = 1; 
     276        struct roar_keyval vals[32]; 
     277        memset(vals, 0, sizeof(vals)); 
     278        char uuid_buf[32][64]; 
     279 
     280        char timebuf[16]; 
     281        snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d",  
     282                        meta->time / 3600, (meta->time % 3600) / 60, meta->time % 60); 
     283 
     284        vals[0].key = g_strdup("LENGTH"); 
     285        vals[0].value = timebuf; 
     286 
     287        for (unsigned i = 0; i < meta->num_items && cnt < 32; i++) 
     288        { 
     289                bool is_uuid = false; 
     290                const char *key = roar_tag_convert(meta->items[i]->type, &is_uuid); 
     291                if (key != NULL) 
     292                { 
     293                        if (is_uuid) 
     294                        { 
     295                                snprintf(uuid_buf[cnt], sizeof(uuid_buf[0]), "{UUID}%s",  
     296                                                meta->items[i]->value); 
     297                                vals[cnt].key = g_strdup(key); 
     298                                vals[cnt].value = uuid_buf[cnt]; 
     299                        } 
     300                        else 
     301                        { 
     302                                vals[cnt].key = g_strdup(key); 
     303                                vals[cnt].value = meta->items[i]->value; 
     304                        } 
     305                        cnt++; 
     306                } 
     307        } 
     308 
     309        roar_vs_meta(self->vss, vals, cnt, &(self->err)); 
     310 
     311        for (unsigned i = 0; i < 32; i++) 
     312                g_free(vals[i].key); 
     313 
     314        g_mutex_unlock(self->lock); 
     315} 
     316 
     317const struct audio_output_plugin roar_output_plugin = { 
     318        .name = "roar", 
     319        .init = roar_init, 
     320        .finish = roar_finish, 
     321        .open = roar_open, 
     322        .play = roar_play, 
     323        .cancel = roar_cancel, 
     324        .close = roar_close, 
     325        .send_tag = roar_send_tag, 
     326 
     327        .mixer_plugin = &roar_mixer_plugin 
     328}; 
     329 
     330 
  • 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; 
    2626extern const struct audio_output_plugin fifo_output_plugin; 
    2727extern const struct audio_output_plugin pipe_output_plugin; 
    2828extern const struct audio_output_plugin alsaPlugin; 
     29extern const struct audio_output_plugin roar_output_plugin; 
    2930extern const struct audio_output_plugin ao_output_plugin; 
    3031extern const struct audio_output_plugin oss_output_plugin; 
    3132extern const struct audio_output_plugin openal_output_plugin; 
    const struct audio_output_plugin *audio_output_plugins[] = { 
    5455#ifdef HAVE_ALSA 
    5556        &alsaPlugin, 
    5657#endif 
     58#ifdef HAVE_ROAR 
     59        &roar_output_plugin, 
     60#endif 
    5761#ifdef HAVE_AO 
    5862        &ao_output_plugin, 
    5963#endif