38 #define VOLUME_MAX_CHANNELS 128 40 typedef struct xmms_volume_map_St {
48 static gpointer xmms_output_monitor_volume_thread (gpointer data);
55 static void xmms_playback_client_seek_samples (
xmms_output_t *output, gint32 samples, gint32 whence,
xmms_error_t *error);
68 static void xmms_playback_client_volume_set (
xmms_output_t *output,
const gchar *channel, gint32 volume,
xmms_error_t *error);
77 static gboolean xmms_output_status_set (
xmms_output_t *output, gint status);
80 static void xmms_output_format_list_free_elem (gpointer data, gpointer user_data);
81 static void xmms_output_format_list_clear (
xmms_output_t *output);
84 #include "output_ipc.c" 104 struct xmms_output_St {
108 gpointer plugin_data;
111 GMutex *playtime_mutex;
118 GThread *filler_thread;
119 GMutex *filler_mutex;
121 GCond *filler_state_cond;
130 GMutex *status_mutex;
144 guint64 bytes_written;
149 gint32 buffer_underruns;
151 GThread *monitor_volume_thread;
152 gboolean monitor_volume_running;
164 g_return_val_if_fail (output, NULL);
165 g_return_val_if_fail (output->plugin, NULL);
167 return output->plugin_data;
173 g_return_if_fail (output);
174 g_return_if_fail (output->plugin);
176 output->plugin_data = data;
185 va_start (ap, output);
189 g_return_if_fail (f);
191 output->format_list = g_list_append (output->format_list, f);
195 xmms_output_format_list_free_elem (gpointer data, gpointer user_data)
199 g_return_if_fail (data);
209 if (output->format_list == NULL)
212 g_list_foreach (output->format_list,
213 xmms_output_format_list_free_elem,
216 g_list_free (output->format_list);
217 output->format_list = NULL;
223 guint buffersize = 0;
225 g_mutex_lock (output->playtime_mutex);
226 output->played += advance;
227 g_mutex_unlock (output->playtime_mutex);
231 if (output->played < buffersize) {
232 buffersize = output->played;
235 g_mutex_lock (output->playtime_mutex);
237 if (output->format) {
239 output->played - buffersize);
240 if ((ms / 100) != (output->played_time / 100)) {
246 output->played_time = ms;
250 g_mutex_unlock (output->playtime_mutex);
257 g_return_if_fail (output);
272 } xmms_output_song_changed_arg_t;
275 song_changed_arg_free (
void *data)
277 xmms_output_song_changed_arg_t *arg = (xmms_output_song_changed_arg_t *)data;
283 song_changed (
void *data)
286 xmms_output_song_changed_arg_t *arg = (xmms_output_song_changed_arg_t *)data;
292 XMMS_DBG (
"Running hotspot! Song changed!! %d", entry);
294 arg->output->played = 0;
295 arg->output->current_entry = entry;
299 if (!xmms_output_format_set (arg->output, type)) {
306 XMMS_DBG (
"Couldn't set format %s/%d/%d, stopping filler..",
307 xmms_sample_name_get (fmt), rate, chn);
309 xmms_output_filler_state_nolock (arg->output,
FILLER_STOP);
326 seek_done (
void *data)
330 g_mutex_lock (output->playtime_mutex);
333 g_mutex_unlock (output->playtime_mutex);
342 output->filler_state = state;
343 g_cond_signal (output->filler_state_cond);
355 g_mutex_lock (output->filler_mutex);
356 xmms_output_filler_state_nolock (output, state);
357 g_mutex_unlock (output->filler_mutex);
360 xmms_output_filler_seek_state (
xmms_output_t *output, guint32 samples)
362 g_mutex_lock (output->filler_mutex);
364 output->filler_seek = samples;
365 g_cond_signal (output->filler_state_cond);
366 g_mutex_unlock (output->filler_mutex);
370 xmms_output_filler (
void *arg)
374 gboolean last_was_kill = FALSE;
379 xmms_error_reset (&err);
383 g_mutex_lock (output->filler_mutex);
391 g_cond_wait (output->filler_state_cond, output->filler_mutex);
392 last_was_kill = FALSE;
400 last_was_kill = TRUE;
408 XMMS_DBG (
"Seek without chain, ignoring..");
419 output->filler_skip = output->filler_seek - ret;
420 if (output->filler_skip < 0) {
421 XMMS_DBG (
"Seeked %d samples too far! Updating position...",
422 -output->filler_skip);
424 output->filler_skip = 0;
425 output->filler_seek = ret;
436 xmms_output_song_changed_arg_t *hsarg;
439 g_mutex_unlock (output->filler_mutex);
443 XMMS_DBG (
"No entry from playlist!");
445 g_mutex_lock (output->filler_mutex);
465 g_mutex_lock (output->filler_mutex);
469 hsarg = g_new0 (xmms_output_song_changed_arg_t, 1);
470 hsarg->output = output;
471 hsarg->chain = chain;
472 hsarg->flush = last_was_kill;
475 last_was_kill = FALSE;
477 g_mutex_lock (output->filler_mutex);
484 XMMS_DBG (
"State changed while waiting...");
487 g_mutex_unlock (output->filler_mutex);
491 g_mutex_lock (output->filler_mutex);
494 gint skip =
MIN (ret, output->toskip);
496 output->toskip -= skip;
501 output->filler_mutex);
506 xmms_error_reset (&err);
517 g_mutex_unlock (output->filler_mutex);
527 xmms_error_reset (&err);
529 g_return_val_if_fail (output, -1);
530 g_return_val_if_fail (buffer, -1);
532 g_mutex_lock (output->filler_mutex);
537 g_mutex_unlock (output->filler_mutex);
540 g_mutex_unlock (output->filler_mutex);
542 update_playtime (output, ret);
553 output->buffer_underruns++;
556 output->bytes_written += ret;
570 g_return_val_if_fail (output->plugin, NULL);
577 g_return_val_if_fail (output->plugin, NULL);
584 g_return_val_if_fail (output, 0);
585 return output->current_entry;
604 g_return_if_fail (output);
607 g_mutex_lock (output->playtime_mutex);
608 ms += output->played_time;
612 g_mutex_unlock (output->playtime_mutex);
615 if (output->format) {
618 xmms_playback_client_seek_samples (output, samples,
627 g_mutex_lock (output->playtime_mutex);
632 g_mutex_unlock (output->playtime_mutex);
636 xmms_output_filler_seek_state (output, samples);
642 g_return_if_fail (output);
644 xmms_output_filler_state (output,
FILLER_RUN);
655 g_return_if_fail (output);
665 g_return_if_fail (output);
677 g_mutex_lock (output->status_mutex);
678 ret = output->status;
679 g_mutex_unlock (output->status_mutex);
686 return output->current_entry;
690 xmms_playback_client_volume_set (
xmms_output_t *output,
const gchar *channel,
694 if (!output->plugin) {
696 "couldn't set volume, output plugin not loaded");
702 "operation not supported");
706 if (volume > 100 || volume < 0) {
713 "couldn't set volume");
723 if (!output->plugin) {
725 "couldn't get volume, output plugin not loaded");
731 "operation not supported");
736 "couldn't get volume");
738 xmms_volume_map_init (&map);
742 NULL, NULL, &map.num_channels)) {
747 g_return_val_if_fail (map.num_channels > 0, NULL);
750 map.names = g_new (
const gchar *, map.num_channels);
751 map.values = g_new (guint, map.num_channels);
754 map.names, map.values,
757 if (!map.status || !map.num_channels) {
761 ret = xmms_volume_map_to_dict (&map);
764 xmms_error_reset (error);
776 g_return_val_if_fail (output, 0);
778 g_mutex_lock (output->playtime_mutex);
779 ret = output->played_time;
780 g_mutex_unlock (output->playtime_mutex);
792 guint buffersize = 0;
794 if (output->format) {
816 if (!output->plugin) {
817 XMMS_DBG (
"No plugin to set status on..");
821 g_mutex_lock (output->status_mutex);
823 if (output->status != status) {
826 XMMS_DBG (
"Can only pause from play.");
829 output->status = status;
833 output->format = NULL;
848 g_mutex_unlock (output->status_mutex);
858 output->monitor_volume_running = FALSE;
859 if (output->monitor_volume_thread) {
860 g_thread_join (output->monitor_volume_thread);
861 output->monitor_volume_thread = NULL;
865 g_thread_join (output->filler_thread);
867 if (output->plugin) {
871 xmms_output_format_list_clear (output);
875 g_mutex_free (output->status_mutex);
876 g_mutex_free (output->playtime_mutex);
877 g_mutex_free (output->filler_mutex);
878 g_cond_free (output->filler_state_cond);
881 xmms_playback_unregister_ipc_commands ();
896 g_return_val_if_fail (output, FALSE);
897 g_return_val_if_fail (new_plugin, FALSE);
899 xmms_playback_client_stop (output, NULL);
901 g_mutex_lock (output->status_mutex);
903 old_plugin = output->plugin;
905 ret = set_plugin (output, new_plugin);
914 }
else if (old_plugin) {
915 XMMS_DBG (
"cannot switch plugin, going back to old one");
916 set_plugin (output, old_plugin);
919 g_mutex_unlock (output->status_mutex);
934 g_return_val_if_fail (playlist, NULL);
940 output->playlist = playlist;
942 output->status_mutex = g_mutex_new ();
943 output->playtime_mutex = g_mutex_new ();
947 XMMS_DBG (
"Using buffersize %d", size);
949 output->filler_mutex = g_mutex_new ();
951 output->filler_state_cond = g_cond_new ();
953 output->filler_thread = g_thread_create (xmms_output_filler, output, TRUE, NULL);
957 xmms_playback_register_ipc_commands (
XMMS_OBJECT (output));
962 if (!set_plugin (output, plugin)) {
966 xmms_log_error (
"initalized output without a plugin, please fix!");
980 g_return_if_fail (output);
991 g_return_val_if_fail (output, FALSE);
992 g_return_val_if_fail (fmt, FALSE);
1000 XMMS_DBG (
"audio formats are equal, not updating");
1008 output->format = fmt;
1015 output->format = fmt;
1017 if (!output->format) {
1020 output->format = fmt;
1035 output->monitor_volume_running = FALSE;
1036 if (output->monitor_volume_thread) {
1037 g_thread_join (output->monitor_volume_thread);
1038 output->monitor_volume_thread = NULL;
1041 if (output->plugin) {
1043 output->plugin = NULL;
1045 xmms_output_format_list_clear (output);
1050 output->plugin = plugin;
1054 output->plugin = NULL;
1055 }
else if (!output->monitor_volume_thread) {
1056 output->monitor_volume_running = TRUE;
1057 output->monitor_volume_thread = g_thread_create (xmms_output_monitor_volume_thread,
1058 output, TRUE, NULL);
1069 for (i = 0; i < vl->num_channels; i++) {
1070 if (!strcmp (vl->names[i], name)) {
1087 if (a->num_channels != b->num_channels) {
1091 for (i = 0; i < a->num_channels; i++) {
1094 j = xmms_volume_map_lookup (b, a->names[i]);
1095 if (j == -1 || b->values[j] != a->values[i]) {
1107 vl->num_channels = 0;
1116 g_free (vl->values);
1124 dst->num_channels = src->num_channels;
1125 dst->status = src->status;
1128 g_free (dst->names);
1131 g_free (dst->values);
1137 dst->names = g_renew (
const gchar *, dst->names, src->num_channels);
1138 dst->values = g_renew (guint, dst->values, src->num_channels);
1140 memcpy (dst->names, src->names, src->num_channels * sizeof (gchar *));
1141 memcpy (dst->values, src->values, src->num_channels * sizeof (guint));
1150 ret = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
1156 for (i = 0; i < vl->num_channels; i++) {
1160 g_tree_replace (ret, (gpointer) vl->names[i], val);
1167 xmms_output_monitor_volume_thread (gpointer data)
1179 xmms_volume_map_init (&old);
1180 xmms_volume_map_init (&cur);
1182 while (output->monitor_volume_running) {
1183 cur.num_channels = 0;
1190 if (cur.num_channels < 1 ||
1194 cur.names = g_renew (
const gchar *, cur.names,
1196 cur.values = g_renew (guint, cur.values, cur.num_channels);
1211 if ((cur.status ^ old.status) ||
1212 (cur.status && old.status &&
1213 !xmms_volume_map_equal (&old, &cur))) {
1216 dict = xmms_volume_map_to_dict (&cur);
1220 g_tree_destroy (dict);
1229 xmms_volume_map_copy (&cur, &old);
1231 g_usleep (G_USEC_PER_SEC);
1234 xmms_volume_map_free (&old);
1235 xmms_volume_map_free (&cur);
gboolean xmms_output_plugin_method_format_set(xmms_output_plugin_t *plugin, xmms_output_t *output, xmms_stream_type_t *st)
struct xmms_ringbuf_St xmms_ringbuf_t
struct xmms_volume_map_St xmms_volume_map_t
guint xmms_sample_ms_to_samples(const xmms_stream_type_t *st, guint milliseconds)
convert from milliseconds to samples for this format.
#define VOLUME_MAX_CHANNELS
void xmms_set_thread_name(const gchar *name)
gint xmms_stream_type_get_int(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
void xmmsv_unref(xmmsv_t *val)
Decreases the references for the xmmsv_t When the number of references reaches 0 it will be freed...
gboolean xmms_ringbuf_iseos(const xmms_ringbuf_t *ringbuf)
Tell if the ringbuffer is EOS.
#define xmms_object_unref(obj)
xmms_config_property_t * xmms_plugin_config_property_register(xmms_plugin_t *plugin, const gchar *name, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
xmms_config_property_t * xmms_output_config_lookup(xmms_output_t *output, const gchar *path)
Lookup a configuration directive for the output plugin.
void xmms_ringbuf_wait_free(const xmms_ringbuf_t *ringbuf, guint len, GMutex *mtx)
Block until we have free space in the ringbuffer.
struct xmms_stream_type_St xmms_stream_type_t
gboolean xmms_output_plugin_method_status(xmms_output_plugin_t *plugin, xmms_output_t *output, gint st)
gint xmms_output_read(xmms_output_t *output, char *buffer, gint len)
Read a number of bytes of data from the output buffer into a buffer.
guint xmms_ringbuf_bytes_used(const xmms_ringbuf_t *ringbuf)
Number of bytes used in the buffer.
xmms_config_property_t * xmms_output_config_property_register(xmms_output_t *output, const gchar *name, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
Register a configuration directive.
guint32 xmms_output_latency(xmms_output_t *output)
const gchar * xmms_plugin_shortname_get(const xmms_plugin_t *plugin)
guint xmms_output_plugin_method_latency_get(xmms_output_plugin_t *plugin, xmms_output_t *output)
gboolean xmms_output_plugin_method_new(xmms_output_plugin_t *plugin, xmms_output_t *output)
guint xmms_sample_bytes_to_ms(const xmms_stream_type_t *st, guint bytes)
Convert from bytes to milliseconds for this format.
gboolean xmms_playlist_advance(xmms_playlist_t *playlist)
Go to next song in playlist according to current playlist mode.
void xmms_output_flush(xmms_output_t *output)
Flush the buffers in soundcard.
void xmms_ringbuf_wait_used(const xmms_ringbuf_t *ringbuf, guint len, GMutex *mtx)
Block until we have used space in the buffer.
void xmms_output_plugin_method_flush(xmms_output_plugin_t *plugin, xmms_output_t *output)
gint xmms_config_property_get_int(const xmms_config_property_t *prop)
Return the value of a config property as an int.
guint xmms_ringbuf_read(xmms_ringbuf_t *ringbuf, gpointer data, guint len)
Reads data from the ringbuffer.
const gchar * xmms_error_message_get(xmms_error_t *err)
Get the human readable error.
gboolean xmms_stream_type_match(const xmms_stream_type_t *in_type, const xmms_stream_type_t *out_type)
xmms_output_t * xmms_output_new(xmms_output_plugin_t *plugin, xmms_playlist_t *playlist)
Allocate a new xmms_output_t.
gboolean xmms_output_plugin_method_volume_set_available(xmms_output_plugin_t *plugin)
#define xmms_log_error(fmt,...)
gboolean xmms_output_plugin_switch(xmms_output_t *output, xmms_output_plugin_t *new_plugin)
Switch to another output plugin.
void xmms_object_emit_f(xmms_object_t *object, guint32 signalid, xmmsv_type_t type,...)
Emits a signal on the current object.
xmms_ringbuf_t * xmms_ringbuf_new(guint size)
Allocate a new ringbuffer.
struct xmms_playlist_St xmms_playlist_t
struct xmms_output_St xmms_output_t
struct xmms_output_plugin_St xmms_output_plugin_t
xmmsv_t * xmmsv_new_int(int32_t i)
Allocates a new integer xmmsv_t.
xmms_medialib_entry_t xmms_output_current_id(xmms_output_t *output)
Get the currently medialib id of the currently played entry.
gpointer xmms_output_private_data_get(xmms_output_t *output)
Retrieve the private data for the plugin that was set with xmms_output_private_data_set.
guint xmms_ringbuf_write_wait(xmms_ringbuf_t *ringbuf, gconstpointer data, guint len, GMutex *mtx)
Same as xmms_ringbuf_write but blocks until there is enough free space.
gboolean xmms_output_plugin_methods_volume_set(xmms_output_plugin_t *plugin, xmms_output_t *output, const gchar *chan, guint val)
gint xmms_output_bytes_available(xmms_output_t *output)
Gets Number of available bytes in the output buffer.
void xmms_ringbuf_clear(xmms_ringbuf_t *ringbuf)
Clear the ringbuffers data.
void xmms_output_stream_type_add(xmms_output_t *output,...)
Add format to list of supported formats.
void xmms_output_private_data_set(xmms_output_t *output, gpointer data)
Set the private data for the plugin that can be retrived with xmms_output_private_data_get later...
#define xmms_object_ref(obj)
gboolean xmms_output_plugin_method_volume_get_available(xmms_output_plugin_t *plugin)
void xmms_ringbuf_set_eos(xmms_ringbuf_t *ringbuf, gboolean eos)
Set EOS flag on ringbuffer.
enum xmms_output_filler_state_E xmms_output_filler_state_t
xmms_output_filler_state_E
gint xmms_sample_frame_size_get(const xmms_stream_type_t *st)
gboolean xmms_output_plugin_format_set_always(xmms_output_plugin_t *plugin)
Check if an output plugin needs format updates on each track change.
#define XMMS_DBG(fmt,...)
void xmms_ringbuf_destroy(xmms_ringbuf_t *ringbuf)
Free all memory used by the ringbuffer.
#define xmms_object_new(objtype, destroyfunc)
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
xmms_config_property_t * xmms_config_property_register(const gchar *path, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
Register a new config property.
xmms_config_property_t * xmms_plugin_config_lookup(xmms_plugin_t *plugin, const gchar *key)
struct xmms_config_property_St xmms_config_property_t
gboolean xmms_output_plugin_method_volume_get(xmms_output_plugin_t *plugin, xmms_output_t *output, const gchar **n, guint *x, guint *y)
xmms_stream_type_t * xmms_stream_type_parse(va_list ap)
xmms_medialib_entry_t xmms_playlist_current_entry(xmms_playlist_t *playlist)
Retrieve the currently active xmms_medialib_entry_t.
void xmms_output_plugin_method_destroy(xmms_output_plugin_t *plugin, xmms_output_t *output)
void xmms_ringbuf_hotspot_set(xmms_ringbuf_t *ringbuf, gboolean(*cb)(void *), void(*destroy)(void *), void *arg)
void(* xmms_object_handler_t)(xmms_object_t *object, xmmsv_t *data, gpointer userdata)
void xmms_output_set_error(xmms_output_t *output, xmms_error_t *error)
Set an error.