//roar.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008 * * This file is part of the XMMS RoarAudio output plugin a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * RoarAudio 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 software; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include //#include "xmms/i18n.h" #include #include #include #include "xmms/plugin.h" #include "xmms/xmmsctrl.h" #include "xmms/dirbrowser.h" #include "xmms/configfile.h" #include "xmms/util.h" #define _(x) (x) gint ctrlsocket_get_session_id(void); void roar_init(void); void roar_about(void); void roar_configure(void); void roar_get_volume(int *l, int *r); void roar_set_volume(int l, int r); void roar_mixer_init(void); void roar_mixer_init_vol(int l, int r); int roar_playing(void); int roar_free(void); void roar_write(void *ptr, int length); void roar_close(void); void roar_flush(int time); void roar_pause(short p); int roar_open(AFormat fmt, int rate, int nch); int roar_get_output_time(void); int roar_get_written_time(void); int roar_update_metadata(void); int roar_chk_metadata(void); OutputPlugin roar_op = { NULL, NULL, "RoarAudio XMMS Plugin", /* Description */ roar_init, roar_about, NULL, //roar_configure, roar_get_volume, roar_set_volume, roar_open, roar_write, roar_close, roar_flush, roar_pause, roar_free, roar_playing, roar_get_output_time, roar_get_written_time, }; #define STATE_CONNECTED 1 #define STATE_PLAYING 2 struct xmms_roar_out { int state; char * server; struct roar_connection con; struct roar_stream stream; int data_fh; long unsigned int written; long unsigned int bps; int session; int pause; } g_inst; OutputPlugin *get_oplugin_info(void) { return &roar_op; } void roar_init(void) { g_inst.state = 0; g_inst.server = NULL; g_inst.session = ctrlsocket_get_session_id(); ROAR_DBG("roar_init(*) = (void)"); } int roar_playing(void) { return FALSE; } void roar_write(void *ptr, int length) { int r; if ( g_inst.pause ) return; ROAR_DBG("roar_write(ptr=%p, length=%i) = (void)", ptr, length); while (length) { if ( (r = write(g_inst.data_fh, ptr, length >= 17640 ? 17640 : length)) != -1 ) { g_inst.written += r; ptr += r; length -= r; } else { return; } } } int roar_open(AFormat fmt, int rate, int nch) { int codec = ROAR_CODEC_DEFAULT; int bits; if ( !(g_inst.state & STATE_CONNECTED) ) { if ( roar_simple_connect(&(g_inst.con), g_inst.server, "XMMS") == -1 ) { return FALSE; } g_inst.state |= STATE_CONNECTED; } bits = 16; switch (fmt) { case FMT_S8: bits = 8; codec = ROAR_CODEC_DEFAULT; break; case FMT_U8: bits = 8; codec = ROAR_CODEC_PCM_U_LE; // _LE, _BE, _PDP,... all the same for 8 bit output break; case FMT_U16_LE: codec = ROAR_CODEC_PCM_U_LE; break; case FMT_U16_BE: codec = ROAR_CODEC_PCM_U_BE; break; case FMT_U16_NE: #if BYTE_ORDER == BIG_ENDIAN codec = ROAR_CODEC_PCM_U_BE; #elif BYTE_ORDER == LITTLE_ENDIAN codec = ROAR_CODEC_PCM_U_LE; #else codec = ROAR_CODEC_PCM_U_PDP; #endif break; case FMT_S16_LE: codec = ROAR_CODEC_PCM_S_LE; break; case FMT_S16_BE: codec = ROAR_CODEC_PCM_S_BE; break; case FMT_S16_NE: codec = ROAR_CODEC_DEFAULT; break; } g_inst.bps = nch * rate * bits / 8; if ( (g_inst.data_fh = roar_simple_new_stream_obj(&(g_inst.con), &(g_inst.stream), rate, nch, bits, codec, ROAR_DIR_PLAY)) == -1) { return FALSE; } g_inst.state |= STATE_PLAYING; g_inst.written = 0; g_inst.pause = 0; roar_update_metadata(); return TRUE; } void roar_close(void) { close(g_inst.data_fh); g_inst.data_fh = -1; g_inst.state |= STATE_PLAYING; g_inst.state -= STATE_PLAYING; g_inst.written = 0; ROAR_DBG("roar_close(void) = (void)"); } void roar_pause(short p) { g_inst.pause = p; } int roar_free(void) { if ( g_inst.pause ) return 0; else return 1000000; // ??? } void roar_flush(int time) { gint64 r = time; r *= g_inst.bps; r /= 1000; g_inst.written = r; } int roar_get_output_time(void) { return roar_get_written_time(); } int roar_get_written_time(void) { gint64 r; if ( !g_inst.bps ) { ROAR_DBG("roar_get_written_time(void) = 0"); return 0; } r = g_inst.written; r *= 1000; // sec -> msec r /= g_inst.bps; ROAR_DBG("roar_get_written_time(void) = %lu", r); return r; } // ABOUT: void roar_about(void) { static GtkWidget *dialog; if (dialog != NULL) return; dialog = xmms_show_message( _("About RoarAudio Plugin"), _("RoarAudio XMMS Plugin..." ), _("OK"), FALSE, NULL, NULL); gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &dialog); } // CONFIG: // META DATA: int roar_update_metadata(void) { struct roar_meta meta; char empty = 0; char * info; int pos; pos = xmms_remote_get_playlist_pos(g_inst.session); meta.value = ∅ meta.key[0] = 0; meta.type = ROAR_META_TYPE_NONE; roar_stream_meta_set(&(g_inst.con), &(g_inst.stream), ROAR_META_MODE_CLEAR, &meta); info = xmms_remote_get_playlist_file(g_inst.session, pos); if ( info ) { if ( strncmp(info, "http:", 5) == 0 ) meta.type = ROAR_META_TYPE_FILEURL; else meta.type = ROAR_META_TYPE_FILENAME; meta.value = info; roar_stream_meta_set(&(g_inst.con), &(g_inst.stream), ROAR_META_MODE_SET, &meta); free(info); } info = xmms_remote_get_playlist_title(g_inst.session, pos); if ( info ) { meta.type = ROAR_META_TYPE_TITLE; meta.value = info; roar_stream_meta_set(&(g_inst.con), &(g_inst.stream), ROAR_META_MODE_SET, &meta); free(info); } return 0; } int roar_chk_metadata(void) { static int old_pos = -1; static char * old_title = "NEW TITLE"; int pos; char * title; int need_update = 0; pos = xmms_remote_get_playlist_pos(g_inst.session); if ( pos != old_pos ) { old_pos = pos; need_update = 1; } else { title = xmms_remote_get_playlist_title(g_inst.session, pos); if ( strcmp(title, old_title) ) { free(old_title); old_title = title; need_update = 1; } else { free(title); } } if ( need_update ) { roar_update_metadata(); } return 0; } // MIXER: void roar_get_volume(int *l, int *r) { int channels; struct roar_mixer_settings mixer; if ( !(g_inst.state & STATE_CONNECTED) ) return; if ( roar_get_vol(&(g_inst.con), g_inst.stream.id, &mixer, &channels) == -1 ) { *l = *r = 100; return; } if ( channels == 1 ) { *l = *r = mixer.mixer[0]/655.35; } else { *l = mixer.mixer[0]/655.35; *r = mixer.mixer[1]/655.35; } } void roar_set_volume(int l, int r) { struct roar_mixer_settings mixer; if ( !(g_inst.state & STATE_CONNECTED) ) return; mixer.mixer[0] = l * 655.35; mixer.mixer[1] = r * 655.35; roar_set_vol(&(g_inst.con), g_inst.stream.id, &mixer, 2); } //ll