/* XMMS2 - X Music Multiplexer System * Copyright (C) 2003-2007 XMMS2 Team * * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ /** * @file * ICES2 based effect */ #include "xmms/xmms_outputplugin.h" #include "xmms/xmms_log.h" #include "xmms/xmms_medialib.h" #include #include #include #include #include #include #include "encode.h" typedef struct xmms_ices_data_St { shout_t *shout; vorbis_comment vc; encoder_state *enc; gint serial; } xmms_ices_data_t; static gboolean xmms_ices_plugin_setup (xmms_output_plugin_t *output_plugin); static gboolean xmms_ices_open (xmms_output_t *output); static gboolean xmms_ices_new (xmms_output_t *output); static void xmms_ices_destroy (xmms_output_t *output); static void xmms_ices_close (xmms_output_t *output); static void xmms_ices_flush (xmms_output_t *output); static void xmms_ices_write (xmms_output_t *output, gpointer buffer, gint len, xmms_error_t *err); static gboolean xmms_ices_format_set (xmms_output_t *output, const xmms_stream_type_t *format); /* static gboolean xmms_oss_volume_set (xmms_output_t *output, const gchar *channel, guint volume); static gboolean xmms_oss_volume_get (xmms_output_t *output, gchar const **names, guint *values, guint *num_channels); */ XMMS_OUTPUT_PLUGIN ("ices", "ICES Output", XMMS_VERSION, "Icecast source output plugin", xmms_ices_plugin_setup); static gboolean xmms_ices_plugin_setup (xmms_output_plugin_t *plugin) { xmms_output_methods_t methods; XMMS_OUTPUT_METHODS_INIT (methods); methods.new = xmms_ices_new; methods.destroy = xmms_ices_destroy; methods.open = xmms_ices_open; methods.close = xmms_ices_close; methods.flush = xmms_ices_flush; methods.format_set_always = xmms_ices_format_set; methods.write = xmms_ices_write; xmms_output_plugin_methods_set (plugin, &methods); xmms_output_plugin_config_property_register (plugin, "encodingnombr", "64000", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "host", "localhost", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "port", "8000", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "password", "hackme", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "user", "source", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "mount", "/stream.ogg", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "public", "0", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "streamname", "", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "streamdescription", "", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "streamgenre", "", NULL, NULL); xmms_output_plugin_config_property_register (plugin, "streamurl", "", NULL, NULL); return TRUE; } static void xmms_ices_flush (xmms_output_t *output) { } static gboolean xmms_ices_open (xmms_output_t *output) { xmms_ices_data_t *data; g_return_val_if_fail (output, FALSE); data = xmms_output_private_data_get (output); g_return_val_if_fail (data, FALSE); if (shout_open (data->shout) == SHOUTERR_SUCCESS) { XMMS_DBG ("Connected to %s:%d/%s", shout_get_host (data->shout), shout_get_port (data->shout), shout_get_mount (data->shout)); } else { xmms_log_error ("Couldn't connect to shoutserver"); return FALSE; } return TRUE; } static void xmms_ices_close (xmms_output_t *output) { xmms_ices_data_t *data; g_return_if_fail (output); data = xmms_output_private_data_get (output); g_return_if_fail (data); shout_close (data->shout); } static void xmms_ices_write (xmms_output_t *output, gpointer buffer, gint len, xmms_error_t *err) { xmms_ices_data_t *data; ogg_page og; g_return_if_fail (output); data = xmms_output_private_data_get (output); g_return_if_fail (data); if (!data->enc) { xmms_error_set (err, XMMS_ERROR_GENERIC, "encoding is not initilized"); return; } encode_data (data->enc, buffer, len, 0); while (encode_dataout (data->enc, &og) > 0) { if (shout_send (data->shout, og.header, og.header_len) < 0) { xmms_error_set (err, XMMS_ERROR_GENERIC, "Disconnected or something."); return; } else if (shout_send (data->shout, og.body, og.body_len) < 0) { xmms_error_set (err, XMMS_ERROR_GENERIC, "Error when sending data to icecast server"); return; } shout_sync (data->shout); } } static gboolean xmms_ices_new (xmms_output_t *output) { xmms_ices_data_t *data; xmms_config_property_t *val; shout_init (); data = g_new0 (xmms_ices_data_t, 1); data->shout = shout_new (); shout_set_format (data->shout, SHOUT_FORMAT_VORBIS); shout_set_protocol (data->shout, SHOUT_PROTOCOL_HTTP); val = xmms_output_config_lookup (output, "host"); shout_set_host (data->shout, xmms_config_property_get_string (val)); val = xmms_output_config_lookup (output, "port"); shout_set_port (data->shout, xmms_config_property_get_int (val)); val = xmms_output_config_lookup (output, "password"); shout_set_password (data->shout, xmms_config_property_get_string (val)); val = xmms_output_config_lookup (output, "user"); shout_set_user (data->shout, xmms_config_property_get_string (val)); shout_set_agent (data->shout, "XMMS/" XMMS_VERSION); val = xmms_output_config_lookup (output, "mount"); shout_set_mount (data->shout, xmms_config_property_get_string (val)); val = xmms_output_config_lookup (output, "public"); shout_set_public (data->shout, xmms_config_property_get_int (val)); val = xmms_output_config_lookup (output, "streamname"); shout_set_name (data->shout, xmms_config_property_get_string (val)); val = xmms_output_config_lookup (output, "streamdescription"); shout_set_description (data->shout, xmms_config_property_get_string (val)); val = xmms_output_config_lookup (output, "streamgenre"); shout_set_genre (data->shout, xmms_config_property_get_string (val)); val = xmms_output_config_lookup (output, "streamurl"); shout_set_url (data->shout, xmms_config_property_get_string (val)); data->serial = 1; xmms_output_private_data_set (output, data); /* static for now */ xmms_output_format_add (output, XMMS_SAMPLE_FORMAT_S16, 2, 44100); return TRUE; } static void xmms_ices_destroy (xmms_output_t *output) { xmms_ices_data_t *data; g_return_if_fail (output); data = xmms_output_private_data_get (output); g_return_if_fail (data); shout_close (data->shout); shout_free (data->shout); shout_shutdown (); } static gboolean xmms_ices_format_set (xmms_output_t *output, const xmms_stream_type_t *format) { xmms_ices_data_t *data; xmms_config_property_t *val; gint nombr; gint rate; gint channels; xmms_medialib_entry_t entry; xmms_medialib_session_t *session; static struct { gchar *prop; gchar *key; } *pptr, props[] = { {XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, "title"}, {XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST, "artist"}, {XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM, "album"}, {NULL, NULL} }; g_return_val_if_fail (output, FALSE); data = xmms_output_private_data_get (output); g_return_val_if_fail (data, FALSE); val = xmms_output_config_lookup (output, "encodingnombr"); nombr = xmms_config_property_get_int (val); XMMS_DBG ("Inited a encoder with rate %d nombr %d", rate, nombr); entry = xmms_output_current_id (output, NULL); vorbis_comment_clear (&data->vc); vorbis_comment_init (&data->vc); session = xmms_medialib_begin (); for (pptr = props; pptr && pptr->prop; pptr++) { const gchar *tmp; tmp = xmms_medialib_entry_property_get_str (session, entry, pptr->prop); if (tmp) { vorbis_comment_add_tag (&data->vc, pptr->key, (gchar *) tmp); } } xmms_medialib_end (session); rate = xmms_stream_type_get_int (format, XMMS_STREAM_TYPE_FMT_SAMPLERATE); channels = xmms_stream_type_get_int (format, XMMS_STREAM_TYPE_FMT_CHANNELS); data->enc = encode_initialise (channels, rate, 1, -1, nombr, -1, 3, data->serial++, &data->vc); return TRUE; }