00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <string.h>
00023 #include <unistd.h>
00024
00025 #include "xmmspriv/xmms_output.h"
00026 #include "xmmspriv/xmms_ringbuf.h"
00027 #include "xmmspriv/xmms_plugin.h"
00028 #include "xmmspriv/xmms_xform.h"
00029 #include "xmmspriv/xmms_sample.h"
00030 #include "xmmspriv/xmms_medialib.h"
00031 #include "xmmspriv/xmms_outputplugin.h"
00032 #include "xmms/xmms_log.h"
00033 #include "xmms/xmms_ipc.h"
00034 #include "xmms/xmms_object.h"
00035 #include "xmms/xmms_config.h"
00036
00037 #define VOLUME_MAX_CHANNELS 128
00038
00039 typedef struct xmms_volume_map_St {
00040 const gchar **names;
00041 guint *values;
00042 guint num_channels;
00043 gboolean status;
00044 } xmms_volume_map_t;
00045
00046 static gboolean xmms_output_format_set (xmms_output_t *output, xmms_stream_type_t *fmt);
00047 static gpointer xmms_output_monitor_volume_thread (gpointer data);
00048
00049 static void xmms_playback_client_start (xmms_output_t *output, xmms_error_t *err);
00050 static void xmms_playback_client_stop (xmms_output_t *output, xmms_error_t *err);
00051 static void xmms_playback_client_pause (xmms_output_t *output, xmms_error_t *err);
00052 static void xmms_playback_client_xform_kill (xmms_output_t *output, xmms_error_t *err);
00053 static void xmms_playback_client_seekms (xmms_output_t *output, gint32 ms, gint32 whence, xmms_error_t *error);
00054 static void xmms_playback_client_seeksamples (xmms_output_t *output, gint32 samples, gint32 whence, xmms_error_t *error);
00055 static gint32 xmms_playback_client_status (xmms_output_t *output, xmms_error_t *error);
00056 static gint xmms_playback_client_current_id (xmms_output_t *output, xmms_error_t *error);
00057 static gint32 xmms_playback_client_playtime (xmms_output_t *output, xmms_error_t *err);
00058
00059 typedef enum xmms_output_filler_state_E {
00060 FILLER_STOP,
00061 FILLER_RUN,
00062 FILLER_QUIT,
00063 FILLER_KILL,
00064 FILLER_SEEK,
00065 } xmms_output_filler_state_t;
00066
00067 static void xmms_playback_client_volume_set (xmms_output_t *output, const gchar *channel, gint32 volume, xmms_error_t *error);
00068 static GTree *xmms_playback_client_volume_get (xmms_output_t *output, xmms_error_t *error);
00069 static void xmms_output_filler_state (xmms_output_t *output, xmms_output_filler_state_t state);
00070 static void xmms_output_filler_state_nolock (xmms_output_t *output, xmms_output_filler_state_t state);
00071
00072 static void xmms_volume_map_init (xmms_volume_map_t *vl);
00073 static void xmms_volume_map_free (xmms_volume_map_t *vl);
00074 static void xmms_volume_map_copy (xmms_volume_map_t *src, xmms_volume_map_t *dst);
00075 static GTree *xmms_volume_map_to_dict (xmms_volume_map_t *vl);
00076 static gboolean xmms_output_status_set (xmms_output_t *output, gint status);
00077 static gboolean set_plugin (xmms_output_t *output, xmms_output_plugin_t *plugin);
00078
00079 static void xmms_output_format_list_free_elem (gpointer data, gpointer user_data);
00080 static void xmms_output_format_list_clear (xmms_output_t *output);
00081 xmms_medialib_entry_t xmms_output_current_id (xmms_output_t *output);
00082
00083 XMMS_CMD_DEFINE (start, xmms_playback_client_start, xmms_output_t *, NONE, NONE, NONE);
00084 XMMS_CMD_DEFINE (stop, xmms_playback_client_stop, xmms_output_t *, NONE, NONE, NONE);
00085 XMMS_CMD_DEFINE (pause, xmms_playback_client_pause, xmms_output_t *, NONE, NONE, NONE);
00086 XMMS_CMD_DEFINE (xform_kill, xmms_playback_client_xform_kill, xmms_output_t *, NONE, NONE, NONE);
00087 XMMS_CMD_DEFINE (playtime, xmms_playback_client_playtime, xmms_output_t *, INT32, NONE, NONE);
00088 XMMS_CMD_DEFINE (seekms, xmms_playback_client_seekms, xmms_output_t *, NONE, INT32, INT32);
00089 XMMS_CMD_DEFINE (seeksamples, xmms_playback_client_seeksamples, xmms_output_t *, NONE, INT32, INT32);
00090 XMMS_CMD_DEFINE (output_status, xmms_playback_client_status, xmms_output_t *, INT32, NONE, NONE);
00091 XMMS_CMD_DEFINE (currentid, xmms_playback_client_current_id, xmms_output_t *, INT32, NONE, NONE);
00092 XMMS_CMD_DEFINE (volume_set, xmms_playback_client_volume_set, xmms_output_t *, NONE, STRING, INT32);
00093 XMMS_CMD_DEFINE (volume_get, xmms_playback_client_volume_get, xmms_output_t *, DICT, NONE, NONE);
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 struct xmms_output_St {
00114 xmms_object_t object;
00115
00116 xmms_output_plugin_t *plugin;
00117 gpointer plugin_data;
00118
00119
00120 GMutex *playtime_mutex;
00121 guint played;
00122 guint played_time;
00123 xmms_medialib_entry_t current_entry;
00124 guint toskip;
00125
00126
00127 GThread *filler_thread;
00128 GMutex *filler_mutex;
00129
00130 GCond *filler_state_cond;
00131 xmms_output_filler_state_t filler_state;
00132
00133 xmms_ringbuf_t *filler_buffer;
00134 guint32 filler_seek;
00135 gint filler_skip;
00136
00137
00138
00139 GMutex *status_mutex;
00140 guint status;
00141
00142 xmms_playlist_t *playlist;
00143
00144
00145 GList *format_list;
00146
00147 xmms_stream_type_t *format;
00148
00149
00150
00151
00152
00153 guint64 bytes_written;
00154
00155
00156
00157
00158 gint32 buffer_underruns;
00159
00160 GThread *monitor_volume_thread;
00161 gboolean monitor_volume_running;
00162 };
00163
00164
00165
00166
00167
00168
00169
00170 gpointer
00171 xmms_output_private_data_get (xmms_output_t *output)
00172 {
00173 g_return_val_if_fail (output, NULL);
00174 g_return_val_if_fail (output->plugin, NULL);
00175
00176 return output->plugin_data;
00177 }
00178
00179 void
00180 xmms_output_private_data_set (xmms_output_t *output, gpointer data)
00181 {
00182 g_return_if_fail (output);
00183 g_return_if_fail (output->plugin);
00184
00185 output->plugin_data = data;
00186 }
00187
00188 void
00189 xmms_output_stream_type_add (xmms_output_t *output, ...)
00190 {
00191 xmms_stream_type_t *f;
00192 va_list ap;
00193
00194 va_start (ap, output);
00195 f = xmms_stream_type_parse (ap);
00196 va_end (ap);
00197
00198 g_return_if_fail (f);
00199
00200 output->format_list = g_list_append (output->format_list, f);
00201 }
00202
00203 static void
00204 xmms_output_format_list_free_elem (gpointer data, gpointer user_data)
00205 {
00206 xmms_stream_type_t *f;
00207
00208 g_return_if_fail (data);
00209
00210 f = data;
00211
00212 xmms_object_unref (f);
00213 }
00214
00215 static void
00216 xmms_output_format_list_clear(xmms_output_t *output)
00217 {
00218 if (output->format_list == NULL)
00219 return;
00220
00221 g_list_foreach (output->format_list,
00222 xmms_output_format_list_free_elem,
00223 NULL);
00224
00225 g_list_free (output->format_list);
00226 output->format_list = NULL;
00227 }
00228
00229 static void
00230 update_playtime (xmms_output_t *output, int advance)
00231 {
00232 guint buffersize = 0;
00233
00234 g_mutex_lock (output->playtime_mutex);
00235 output->played += advance;
00236 g_mutex_unlock (output->playtime_mutex);
00237
00238 buffersize = xmms_output_plugin_method_latency_get (output->plugin, output);
00239
00240 if (output->played < buffersize) {
00241 buffersize = output->played;
00242 }
00243
00244 g_mutex_lock (output->playtime_mutex);
00245
00246 if (output->format) {
00247 guint ms = xmms_sample_bytes_to_ms (output->format,
00248 output->played - buffersize);
00249 if ((ms / 100) != (output->played_time / 100)) {
00250 xmms_object_emit_f (XMMS_OBJECT (output),
00251 XMMS_IPC_SIGNAL_PLAYBACK_PLAYTIME,
00252 XMMSV_TYPE_INT32,
00253 ms);
00254 }
00255 output->played_time = ms;
00256
00257 }
00258
00259 g_mutex_unlock (output->playtime_mutex);
00260
00261 }
00262
00263 void
00264 xmms_output_set_error (xmms_output_t *output, xmms_error_t *error)
00265 {
00266 g_return_if_fail (output);
00267
00268 xmms_output_status_set (output, XMMS_PLAYBACK_STATUS_STOP);
00269
00270 if (error) {
00271 xmms_log_error ("Output plugin %s reported error, '%s'",
00272 xmms_plugin_shortname_get ((xmms_plugin_t *)output->plugin),
00273 xmms_error_message_get (error));
00274 }
00275 }
00276
00277 typedef struct {
00278 xmms_output_t *output;
00279 xmms_xform_t *chain;
00280 gboolean flush;
00281 } xmms_output_song_changed_arg_t;
00282
00283 static void
00284 song_changed_arg_free (void *data)
00285 {
00286 xmms_output_song_changed_arg_t *arg = (xmms_output_song_changed_arg_t *)data;
00287 xmms_object_unref (arg->chain);
00288 g_free (arg);
00289 }
00290
00291 static gboolean
00292 song_changed (void *data)
00293 {
00294
00295 xmms_output_song_changed_arg_t *arg = (xmms_output_song_changed_arg_t *)data;
00296 xmms_medialib_entry_t entry;
00297 xmms_stream_type_t *type;
00298
00299 entry = xmms_xform_entry_get (arg->chain);
00300
00301 XMMS_DBG ("Running hotspot! Song changed!! %d", entry);
00302
00303 arg->output->played = 0;
00304 arg->output->current_entry = entry;
00305
00306 type = xmms_xform_outtype_get (arg->chain);
00307
00308 if (!xmms_output_format_set (arg->output, type)) {
00309 gint fmt, rate, chn;
00310
00311 fmt = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_FORMAT);
00312 rate = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00313 chn = xmms_stream_type_get_int (type, XMMS_STREAM_TYPE_FMT_CHANNELS);
00314
00315 XMMS_DBG ("Couldn't set format %s/%d/%d, stopping filler..",
00316 xmms_sample_name_get (fmt), rate, chn);
00317
00318 xmms_output_filler_state_nolock (arg->output, FILLER_STOP);
00319 xmms_ringbuf_set_eos (arg->output->filler_buffer, TRUE);
00320 return FALSE;
00321 }
00322
00323 if (arg->flush)
00324 xmms_output_flush (arg->output);
00325
00326 xmms_object_emit_f (XMMS_OBJECT (arg->output),
00327 XMMS_IPC_SIGNAL_PLAYBACK_CURRENTID,
00328 XMMSV_TYPE_INT32,
00329 entry);
00330
00331 return TRUE;
00332 }
00333
00334 static gboolean
00335 seek_done (void *data)
00336 {
00337 xmms_output_t *output = (xmms_output_t *)data;
00338
00339 g_mutex_lock (output->playtime_mutex);
00340 output->played = output->filler_seek * xmms_sample_frame_size_get (output->format);
00341 output->toskip = output->filler_skip * xmms_sample_frame_size_get (output->format);
00342 g_mutex_unlock (output->playtime_mutex);
00343
00344 xmms_output_flush (output);
00345 return TRUE;
00346 }
00347
00348 static void
00349 xmms_output_filler_state_nolock (xmms_output_t *output, xmms_output_filler_state_t state)
00350 {
00351 output->filler_state = state;
00352 g_cond_signal (output->filler_state_cond);
00353 if (state == FILLER_QUIT || state == FILLER_STOP || state == FILLER_KILL) {
00354 xmms_ringbuf_clear (output->filler_buffer);
00355 }
00356 if (state != FILLER_STOP) {
00357 xmms_ringbuf_set_eos (output->filler_buffer, FALSE);
00358 }
00359 }
00360
00361 static void
00362 xmms_output_filler_state (xmms_output_t *output, xmms_output_filler_state_t state)
00363 {
00364 g_mutex_lock (output->filler_mutex);
00365 xmms_output_filler_state_nolock (output, state);
00366 g_mutex_unlock (output->filler_mutex);
00367 }
00368 static void
00369 xmms_output_filler_seek_state (xmms_output_t *output, guint32 samples)
00370 {
00371 g_mutex_lock (output->filler_mutex);
00372 output->filler_state = FILLER_SEEK;
00373 output->filler_seek = samples;
00374 g_cond_signal (output->filler_state_cond);
00375 g_mutex_unlock (output->filler_mutex);
00376 }
00377
00378 static void *
00379 xmms_output_filler (void *arg)
00380 {
00381 xmms_output_t *output = (xmms_output_t *)arg;
00382 xmms_xform_t *chain = NULL;
00383 gboolean last_was_kill = FALSE;
00384 char buf[4096];
00385 xmms_error_t err;
00386 gint ret;
00387
00388 xmms_error_reset (&err);
00389
00390 g_mutex_lock (output->filler_mutex);
00391 while (output->filler_state != FILLER_QUIT) {
00392 if (output->filler_state == FILLER_STOP) {
00393 if (chain) {
00394 xmms_object_unref (chain);
00395 chain = NULL;
00396 }
00397 xmms_ringbuf_set_eos (output->filler_buffer, TRUE);
00398 g_cond_wait (output->filler_state_cond, output->filler_mutex);
00399 last_was_kill = FALSE;
00400 continue;
00401 }
00402 if (output->filler_state == FILLER_KILL) {
00403 if (chain) {
00404 xmms_object_unref (chain);
00405 chain = NULL;
00406 output->filler_state = FILLER_RUN;
00407 last_was_kill = TRUE;
00408 } else {
00409 output->filler_state = FILLER_STOP;
00410 }
00411 continue;
00412 }
00413 if (output->filler_state == FILLER_SEEK) {
00414 if (!chain) {
00415 XMMS_DBG ("Seek without chain, ignoring..");
00416 output->filler_state = FILLER_STOP;
00417 continue;
00418 }
00419
00420 ret = xmms_xform_this_seek (chain, output->filler_seek, XMMS_XFORM_SEEK_SET, &err);
00421 if (ret == -1) {
00422 XMMS_DBG ("Seeking failed: %s", xmms_error_message_get (&err));
00423 } else {
00424 XMMS_DBG ("Seek ok! %d", ret);
00425
00426 output->filler_skip = output->filler_seek - ret;
00427 if (output->filler_skip < 0) {
00428 XMMS_DBG ("Seeked %d samples too far! Updating position...",
00429 -output->filler_skip);
00430
00431 output->filler_skip = 0;
00432 output->filler_seek = ret;
00433 }
00434
00435 xmms_ringbuf_clear (output->filler_buffer);
00436 xmms_ringbuf_hotspot_set (output->filler_buffer, seek_done, NULL, output);
00437 }
00438 output->filler_state = FILLER_RUN;
00439 }
00440
00441 if (!chain) {
00442 xmms_medialib_entry_t entry;
00443 xmms_output_song_changed_arg_t *hsarg;
00444 xmms_medialib_session_t *session;
00445
00446 g_mutex_unlock (output->filler_mutex);
00447
00448 entry = xmms_playlist_current_entry (output->playlist);
00449 if (!entry) {
00450 XMMS_DBG ("No entry from playlist!");
00451 output->filler_state = FILLER_STOP;
00452 g_mutex_lock (output->filler_mutex);
00453 continue;
00454 }
00455
00456 chain = xmms_xform_chain_setup (entry, output->format_list, FALSE);
00457 if (!chain) {
00458 session = xmms_medialib_begin_write ();
00459 if (xmms_medialib_entry_property_get_int (session, entry, XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS) == XMMS_MEDIALIB_ENTRY_STATUS_NEW) {
00460 xmms_medialib_end (session);
00461 xmms_medialib_entry_remove (entry);
00462 } else {
00463 xmms_medialib_entry_status_set (session, entry, XMMS_MEDIALIB_ENTRY_STATUS_NOT_AVAILABLE);
00464 xmms_medialib_entry_send_update (entry);
00465 xmms_medialib_end (session);
00466 }
00467
00468 if (!xmms_playlist_advance (output->playlist)) {
00469 XMMS_DBG ("End of playlist");
00470 output->filler_state = FILLER_STOP;
00471 }
00472 g_mutex_lock (output->filler_mutex);
00473 continue;
00474 }
00475
00476 hsarg = g_new0 (xmms_output_song_changed_arg_t, 1);
00477 hsarg->output = output;
00478 hsarg->chain = chain;
00479 hsarg->flush = last_was_kill;
00480 xmms_object_ref (chain);
00481
00482 last_was_kill = FALSE;
00483
00484 g_mutex_lock (output->filler_mutex);
00485 xmms_ringbuf_hotspot_set (output->filler_buffer, song_changed, song_changed_arg_free, hsarg);
00486 }
00487
00488 xmms_ringbuf_wait_free (output->filler_buffer, sizeof (buf), output->filler_mutex);
00489
00490 if (output->filler_state != FILLER_RUN) {
00491 XMMS_DBG ("State changed while waiting...");
00492 continue;
00493 }
00494 g_mutex_unlock (output->filler_mutex);
00495
00496 ret = xmms_xform_this_read (chain, buf, sizeof (buf), &err);
00497
00498 g_mutex_lock (output->filler_mutex);
00499
00500 if (ret > 0) {
00501 gint skip = MIN (ret, output->toskip);
00502
00503 output->toskip -= skip;
00504 if (ret > skip) {
00505 xmms_ringbuf_write_wait (output->filler_buffer,
00506 buf + skip,
00507 ret - skip,
00508 output->filler_mutex);
00509 }
00510 } else {
00511 if (ret == -1) {
00512
00513 xmms_error_reset (&err);
00514 }
00515 xmms_object_unref (chain);
00516 chain = NULL;
00517 if (!xmms_playlist_advance (output->playlist)) {
00518 XMMS_DBG ("End of playlist");
00519 output->filler_state = FILLER_STOP;
00520 }
00521 }
00522
00523 }
00524 g_mutex_unlock (output->filler_mutex);
00525 return NULL;
00526 }
00527
00528 gint
00529 xmms_output_read (xmms_output_t *output, char *buffer, gint len)
00530 {
00531 gint ret;
00532 xmms_error_t err;
00533
00534 xmms_error_reset (&err);
00535
00536 g_return_val_if_fail (output, -1);
00537 g_return_val_if_fail (buffer, -1);
00538
00539 g_mutex_lock (output->filler_mutex);
00540 xmms_ringbuf_wait_used (output->filler_buffer, len, output->filler_mutex);
00541 ret = xmms_ringbuf_read (output->filler_buffer, buffer, len);
00542 if (ret == 0 && xmms_ringbuf_iseos (output->filler_buffer)) {
00543 xmms_output_status_set (output, XMMS_PLAYBACK_STATUS_STOP);
00544 g_mutex_unlock (output->filler_mutex);
00545 return -1;
00546 }
00547 g_mutex_unlock (output->filler_mutex);
00548
00549 update_playtime (output, ret);
00550
00551 if (ret < len) {
00552 XMMS_DBG ("Underrun %d of %d (%d)", ret, len, xmms_sample_frame_size_get (output->format));
00553
00554 if ((ret % xmms_sample_frame_size_get (output->format)) != 0) {
00555 xmms_log_error ("***********************************");
00556 xmms_log_error ("* Read non-multiple of sample size,");
00557 xmms_log_error ("* you probably hear noise now :)");
00558 xmms_log_error ("***********************************");
00559 }
00560 output->buffer_underruns++;
00561 }
00562
00563 output->bytes_written += ret;
00564
00565 return ret;
00566 }
00567
00568 xmms_config_property_t *
00569 xmms_output_config_property_register (xmms_output_t *output, const gchar *name, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
00570 {
00571 g_return_val_if_fail (output->plugin, NULL);
00572 return xmms_plugin_config_property_register ((xmms_plugin_t *)output->plugin, name, default_value, cb, userdata);
00573 }
00574
00575 xmms_config_property_t *
00576 xmms_output_config_lookup (xmms_output_t *output, const gchar *path)
00577 {
00578 g_return_val_if_fail (output->plugin, NULL);
00579 return xmms_plugin_config_lookup ((xmms_plugin_t *)output->plugin, path);
00580 }
00581
00582 xmms_medialib_entry_t
00583 xmms_output_current_id (xmms_output_t *output)
00584 {
00585 g_return_val_if_fail (output, 0);
00586 return output->current_entry;
00587 }
00588
00589
00590
00591
00592
00593
00594 static void
00595 xmms_playback_client_xform_kill (xmms_output_t *output, xmms_error_t *error)
00596 {
00597 xmms_output_filler_state (output, FILLER_KILL);
00598 }
00599
00600 static void
00601 xmms_playback_client_seekms (xmms_output_t *output, gint32 ms, gint32 whence, xmms_error_t *error)
00602 {
00603 guint samples;
00604
00605 g_return_if_fail (output);
00606
00607 if (whence == XMMS_PLAYBACK_SEEK_CUR) {
00608 g_mutex_lock (output->playtime_mutex);
00609 ms += output->played_time;
00610 if (ms < 0) {
00611 ms = 0;
00612 }
00613 g_mutex_unlock (output->playtime_mutex);
00614 }
00615
00616 if (output->format) {
00617 samples = xmms_sample_ms_to_samples (output->format, ms);
00618
00619 xmms_playback_client_seeksamples (output, samples,
00620 XMMS_PLAYBACK_SEEK_SET, error);
00621 }
00622 }
00623
00624 static void
00625 xmms_playback_client_seeksamples (xmms_output_t *output, gint32 samples, gint32 whence, xmms_error_t *error)
00626 {
00627 if (whence == XMMS_PLAYBACK_SEEK_CUR) {
00628 g_mutex_lock (output->playtime_mutex);
00629 samples += output->played / xmms_sample_frame_size_get (output->format);
00630 if (samples < 0) {
00631 samples = 0;
00632 }
00633 g_mutex_unlock (output->playtime_mutex);
00634 }
00635
00636
00637 xmms_output_filler_seek_state (output, samples);
00638 }
00639
00640 static void
00641 xmms_playback_client_start (xmms_output_t *output, xmms_error_t *err)
00642 {
00643 g_return_if_fail (output);
00644
00645 xmms_output_filler_state (output, FILLER_RUN);
00646 if (!xmms_output_status_set (output, XMMS_PLAYBACK_STATUS_PLAY)) {
00647 xmms_output_filler_state (output, FILLER_STOP);
00648 xmms_error_set (err, XMMS_ERROR_GENERIC, "Could not start playback");
00649 }
00650
00651 }
00652
00653 static void
00654 xmms_playback_client_stop (xmms_output_t *output, xmms_error_t *err)
00655 {
00656 g_return_if_fail (output);
00657
00658 xmms_output_status_set (output, XMMS_PLAYBACK_STATUS_STOP);
00659
00660 xmms_output_filler_state (output, FILLER_STOP);
00661 }
00662
00663 static void
00664 xmms_playback_client_pause (xmms_output_t *output, xmms_error_t *err)
00665 {
00666 g_return_if_fail (output);
00667
00668 xmms_output_status_set (output, XMMS_PLAYBACK_STATUS_PAUSE);
00669 }
00670
00671
00672 static gint32
00673 xmms_playback_client_status (xmms_output_t *output, xmms_error_t *error)
00674 {
00675 gint32 ret;
00676 g_return_val_if_fail (output, XMMS_PLAYBACK_STATUS_STOP);
00677
00678 g_mutex_lock (output->status_mutex);
00679 ret = output->status;
00680 g_mutex_unlock (output->status_mutex);
00681 return ret;
00682 }
00683
00684 static gint
00685 xmms_playback_client_current_id (xmms_output_t *output, xmms_error_t *error)
00686 {
00687 return output->current_entry;
00688 }
00689
00690 static void
00691 xmms_playback_client_volume_set (xmms_output_t *output, const gchar *channel,
00692 gint32 volume, xmms_error_t *error)
00693 {
00694
00695 if (!output->plugin) {
00696 xmms_error_set (error, XMMS_ERROR_GENERIC,
00697 "couldn't set volume, output plugin not loaded");
00698 return;
00699 }
00700
00701 if (!xmms_output_plugin_method_volume_set_available (output->plugin)) {
00702 xmms_error_set (error, XMMS_ERROR_GENERIC,
00703 "operation not supported");
00704 return;
00705 }
00706
00707 if (volume > 100) {
00708 xmms_error_set (error, XMMS_ERROR_INVAL, "volume out of range");
00709 return;
00710 }
00711
00712 if (!xmms_output_plugin_methods_volume_set (output->plugin, output, channel, volume)) {
00713 xmms_error_set (error, XMMS_ERROR_GENERIC,
00714 "couldn't set volume");
00715 }
00716 }
00717
00718 static GTree *
00719 xmms_playback_client_volume_get (xmms_output_t *output, xmms_error_t *error)
00720 {
00721 GTree *ret;
00722 xmms_volume_map_t map;
00723
00724 if (!output->plugin) {
00725 xmms_error_set (error, XMMS_ERROR_GENERIC,
00726 "couldn't get volume, output plugin not loaded");
00727 return NULL;
00728 }
00729
00730 if (!xmms_output_plugin_method_volume_get_available (output->plugin)) {
00731 xmms_error_set (error, XMMS_ERROR_GENERIC,
00732 "operation not supported");
00733 return NULL;
00734 }
00735
00736 xmms_error_set (error, XMMS_ERROR_GENERIC,
00737 "couldn't get volume");
00738
00739 xmms_volume_map_init (&map);
00740
00741
00742 if (!xmms_output_plugin_method_volume_get (output->plugin, output,
00743 NULL, NULL, &map.num_channels)) {
00744 return NULL;
00745 }
00746
00747
00748 g_return_val_if_fail (map.num_channels > 0, NULL);
00749 g_return_val_if_fail (map.num_channels <= VOLUME_MAX_CHANNELS, NULL);
00750
00751 map.names = g_new (const gchar *, map.num_channels);
00752 map.values = g_new (guint, map.num_channels);
00753
00754 map.status = xmms_output_plugin_method_volume_get (output->plugin, output,
00755 map.names, map.values,
00756 &map.num_channels);
00757
00758 if (!map.status || !map.num_channels) {
00759 return NULL;
00760 }
00761
00762 ret = xmms_volume_map_to_dict (&map);
00763
00764
00765 xmms_error_reset (error);
00766
00767 return ret;
00768 }
00769
00770
00771
00772
00773 static gint32
00774 xmms_playback_client_playtime (xmms_output_t *output, xmms_error_t *error)
00775 {
00776 guint32 ret;
00777 g_return_val_if_fail (output, 0);
00778
00779 g_mutex_lock (output->playtime_mutex);
00780 ret = output->played_time;
00781 g_mutex_unlock (output->playtime_mutex);
00782
00783 return ret;
00784 }
00785
00786
00787
00788
00789 guint32
00790 xmms_output_latency (xmms_output_t *output)
00791 {
00792 guint ret = 0;
00793 guint buffersize = 0;
00794
00795 if (output->format) {
00796
00797 buffersize += xmms_ringbuf_bytes_used (output->filler_buffer);
00798
00799
00800 buffersize += xmms_output_plugin_method_latency_get (output->plugin, output);
00801
00802 ret = xmms_sample_bytes_to_ms (output->format, buffersize);
00803 }
00804
00805 return ret;
00806 }
00807
00808
00809
00810
00811
00812 static gboolean
00813 xmms_output_status_set (xmms_output_t *output, gint status)
00814 {
00815 gboolean ret = TRUE;
00816
00817 if (!output->plugin) {
00818 XMMS_DBG ("No plugin to set status on..");
00819 return FALSE;
00820 }
00821
00822 g_mutex_lock (output->status_mutex);
00823
00824 if (output->status != status) {
00825 if (status == XMMS_PLAYBACK_STATUS_PAUSE &&
00826 output->status != XMMS_PLAYBACK_STATUS_PLAY) {
00827 XMMS_DBG ("Can only pause from play.");
00828 ret = FALSE;
00829 } else {
00830 output->status = status;
00831
00832 if (status == XMMS_PLAYBACK_STATUS_STOP) {
00833 xmms_object_unref (output->format);
00834 output->format = NULL;
00835 }
00836 if (!xmms_output_plugin_method_status (output->plugin, output, status)) {
00837 xmms_log_error ("Status method returned an error!");
00838 output->status = XMMS_PLAYBACK_STATUS_STOP;
00839 ret = FALSE;
00840 }
00841
00842 xmms_object_emit_f (XMMS_OBJECT (output),
00843 XMMS_IPC_SIGNAL_PLAYBACK_STATUS,
00844 XMMSV_TYPE_INT32,
00845 output->status);
00846 }
00847 }
00848
00849 g_mutex_unlock (output->status_mutex);
00850
00851 return ret;
00852 }
00853
00854 static void
00855 xmms_output_destroy (xmms_object_t *object)
00856 {
00857 xmms_output_t *output = (xmms_output_t *)object;
00858
00859 output->monitor_volume_running = FALSE;
00860 if (output->monitor_volume_thread) {
00861 g_thread_join (output->monitor_volume_thread);
00862 output->monitor_volume_thread = NULL;
00863 }
00864
00865 xmms_output_filler_state (output, FILLER_QUIT);
00866 g_thread_join (output->filler_thread);
00867
00868 if (output->plugin) {
00869 xmms_output_plugin_method_destroy (output->plugin, output);
00870 xmms_object_unref (output->plugin);
00871 }
00872 xmms_output_format_list_clear (output);
00873
00874 xmms_object_unref (output->playlist);
00875
00876 g_mutex_free (output->status_mutex);
00877 g_mutex_free (output->playtime_mutex);
00878 g_mutex_free (output->filler_mutex);
00879 g_cond_free (output->filler_state_cond);
00880 xmms_ringbuf_destroy (output->filler_buffer);
00881
00882 xmms_ipc_broadcast_unregister ( XMMS_IPC_SIGNAL_PLAYBACK_VOLUME_CHANGED);
00883 xmms_ipc_broadcast_unregister ( XMMS_IPC_SIGNAL_PLAYBACK_STATUS);
00884 xmms_ipc_broadcast_unregister ( XMMS_IPC_SIGNAL_PLAYBACK_CURRENTID);
00885 xmms_ipc_signal_unregister (XMMS_IPC_SIGNAL_PLAYBACK_PLAYTIME);
00886 xmms_ipc_object_unregister (XMMS_IPC_OBJECT_PLAYBACK);
00887 }
00888
00889
00890
00891
00892
00893
00894
00895 gboolean
00896 xmms_output_plugin_switch (xmms_output_t *output, xmms_output_plugin_t *new_plugin)
00897 {
00898 xmms_output_plugin_t *old_plugin;
00899 gboolean ret;
00900
00901 g_return_val_if_fail (output, FALSE);
00902 g_return_val_if_fail (new_plugin, FALSE);
00903
00904 xmms_playback_client_stop (output, NULL);
00905
00906 g_mutex_lock (output->status_mutex);
00907
00908 old_plugin = output->plugin;
00909
00910 ret = set_plugin (output, new_plugin);
00911
00912
00913
00914
00915
00916
00917 if (ret) {
00918 xmms_object_unref (old_plugin);
00919 } else if (old_plugin) {
00920 XMMS_DBG ("cannot switch plugin, going back to old one");
00921 set_plugin (output, old_plugin);
00922 }
00923
00924 g_mutex_unlock (output->status_mutex);
00925
00926 return ret;
00927 }
00928
00929
00930
00931
00932 xmms_output_t *
00933 xmms_output_new (xmms_output_plugin_t *plugin, xmms_playlist_t *playlist)
00934 {
00935 xmms_output_t *output;
00936 xmms_config_property_t *prop;
00937 gint size;
00938
00939 g_return_val_if_fail (playlist, NULL);
00940
00941 XMMS_DBG ("Trying to open output");
00942
00943 output = xmms_object_new (xmms_output_t, xmms_output_destroy);
00944
00945 output->playlist = playlist;
00946
00947 output->status_mutex = g_mutex_new ();
00948 output->playtime_mutex = g_mutex_new ();
00949
00950 prop = xmms_config_property_register ("output.buffersize", "32768", NULL, NULL);
00951 size = xmms_config_property_get_int (prop);
00952 XMMS_DBG ("Using buffersize %d", size);
00953
00954 output->filler_mutex = g_mutex_new ();
00955 output->filler_state = FILLER_STOP;
00956 output->filler_state_cond = g_cond_new ();
00957 output->filler_buffer = xmms_ringbuf_new (size);
00958 output->filler_thread = g_thread_create (xmms_output_filler, output, TRUE, NULL);
00959
00960 xmms_config_property_register ("output.flush_on_pause", "1", NULL, NULL);
00961 xmms_ipc_object_register (XMMS_IPC_OBJECT_PLAYBACK, XMMS_OBJECT (output));
00962
00963
00964
00965 xmms_ipc_broadcast_register (XMMS_OBJECT (output),
00966 XMMS_IPC_SIGNAL_PLAYBACK_VOLUME_CHANGED);
00967 xmms_ipc_broadcast_register (XMMS_OBJECT (output),
00968 XMMS_IPC_SIGNAL_PLAYBACK_STATUS);
00969 xmms_ipc_broadcast_register (XMMS_OBJECT (output),
00970 XMMS_IPC_SIGNAL_PLAYBACK_CURRENTID);
00971
00972
00973
00974 xmms_ipc_signal_register (XMMS_OBJECT (output),
00975 XMMS_IPC_SIGNAL_PLAYBACK_PLAYTIME);
00976
00977
00978 xmms_object_cmd_add (XMMS_OBJECT (output),
00979 XMMS_IPC_CMD_START,
00980 XMMS_CMD_FUNC (start));
00981 xmms_object_cmd_add (XMMS_OBJECT (output),
00982 XMMS_IPC_CMD_STOP,
00983 XMMS_CMD_FUNC (stop));
00984 xmms_object_cmd_add (XMMS_OBJECT (output),
00985 XMMS_IPC_CMD_PAUSE,
00986 XMMS_CMD_FUNC (pause));
00987 xmms_object_cmd_add (XMMS_OBJECT (output),
00988 XMMS_IPC_CMD_DECODER_KILL,
00989 XMMS_CMD_FUNC (xform_kill));
00990 xmms_object_cmd_add (XMMS_OBJECT (output),
00991 XMMS_IPC_CMD_CPLAYTIME,
00992 XMMS_CMD_FUNC (playtime));
00993 xmms_object_cmd_add (XMMS_OBJECT (output),
00994 XMMS_IPC_CMD_SEEKMS,
00995 XMMS_CMD_FUNC (seekms));
00996 xmms_object_cmd_add (XMMS_OBJECT (output),
00997 XMMS_IPC_CMD_SEEKSAMPLES,
00998 XMMS_CMD_FUNC (seeksamples));
00999 xmms_object_cmd_add (XMMS_OBJECT (output),
01000 XMMS_IPC_CMD_PLAYBACK_STATUS,
01001 XMMS_CMD_FUNC (output_status));
01002 xmms_object_cmd_add (XMMS_OBJECT (output),
01003 XMMS_IPC_CMD_CURRENTID,
01004 XMMS_CMD_FUNC (currentid));
01005 xmms_object_cmd_add (XMMS_OBJECT (output),
01006 XMMS_IPC_CMD_VOLUME_SET,
01007 XMMS_CMD_FUNC (volume_set));
01008 xmms_object_cmd_add (XMMS_OBJECT (output),
01009 XMMS_IPC_CMD_VOLUME_GET,
01010 XMMS_CMD_FUNC (volume_get));
01011
01012 output->status = XMMS_PLAYBACK_STATUS_STOP;
01013
01014 if (plugin) {
01015 if (!set_plugin (output, plugin)) {
01016 xmms_log_error ("Could not initialize output plugin");
01017 }
01018 } else {
01019 xmms_log_error ("initalized output without a plugin, please fix!");
01020 }
01021
01022
01023
01024 return output;
01025 }
01026
01027
01028
01029
01030 void
01031 xmms_output_flush (xmms_output_t *output)
01032 {
01033 g_return_if_fail (output);
01034
01035 xmms_output_plugin_method_flush (output->plugin, output);
01036 }
01037
01038
01039
01040
01041 static gboolean
01042 xmms_output_format_set (xmms_output_t *output, xmms_stream_type_t *fmt)
01043 {
01044 g_return_val_if_fail (output, FALSE);
01045 g_return_val_if_fail (fmt, FALSE);
01046
01047 XMMS_DBG ("Setting format!");
01048
01049 if (!xmms_output_plugin_format_set_always (output->plugin)) {
01050 gboolean ret;
01051
01052 if (output->format && xmms_stream_type_match (output->format, fmt)) {
01053 XMMS_DBG ("audio formats are equal, not updating");
01054 return TRUE;
01055 }
01056
01057 ret = xmms_output_plugin_method_format_set (output->plugin, output, fmt);
01058 if (ret) {
01059 xmms_object_unref (output->format);
01060 xmms_object_ref (fmt);
01061 output->format = fmt;
01062 }
01063 return ret;
01064 } else {
01065 if (output->format && !xmms_stream_type_match (output->format, fmt)) {
01066 xmms_object_unref (output->format);
01067 xmms_object_ref (fmt);
01068 output->format = fmt;
01069 }
01070 if (!output->format) {
01071 xmms_object_unref (output->format);
01072 xmms_object_ref (fmt);
01073 output->format = fmt;
01074 }
01075 return xmms_output_plugin_method_format_set (output->plugin, output, output->format);
01076 }
01077 }
01078
01079
01080 static gboolean
01081 set_plugin (xmms_output_t *output, xmms_output_plugin_t *plugin)
01082 {
01083 gboolean ret;
01084
01085 g_assert (output);
01086 g_assert (plugin);
01087
01088 output->monitor_volume_running = FALSE;
01089 if (output->monitor_volume_thread) {
01090 g_thread_join (output->monitor_volume_thread);
01091 output->monitor_volume_thread = NULL;
01092 }
01093
01094 if (output->plugin) {
01095 xmms_output_plugin_method_destroy (output->plugin, output);
01096 output->plugin = NULL;
01097 }
01098 xmms_output_format_list_clear (output);
01099
01100
01101
01102
01103 output->plugin = plugin;
01104 ret = xmms_output_plugin_method_new (output->plugin, output);
01105
01106 if (!ret) {
01107 output->plugin = NULL;
01108 } else if (!output->monitor_volume_thread) {
01109 output->monitor_volume_running = TRUE;
01110 output->monitor_volume_thread = g_thread_create (xmms_output_monitor_volume_thread,
01111 output, TRUE, NULL);
01112 }
01113
01114 return ret;
01115 }
01116
01117 static gint
01118 xmms_volume_map_lookup (xmms_volume_map_t *vl, const gchar *name)
01119 {
01120 gint i;
01121
01122 for (i = 0; i < vl->num_channels; i++) {
01123 if (!strcmp (vl->names[i], name)) {
01124 return i;
01125 }
01126 }
01127
01128 return -1;
01129 }
01130
01131
01132 static gboolean
01133 xmms_volume_map_equal (xmms_volume_map_t *a, xmms_volume_map_t *b)
01134 {
01135 guint i;
01136
01137 g_assert (a);
01138 g_assert (b);
01139
01140 if (a->num_channels != b->num_channels) {
01141 return FALSE;
01142 }
01143
01144 for (i = 0; i < a->num_channels; i++) {
01145 gint j;
01146
01147 j = xmms_volume_map_lookup (b, a->names[i]);
01148 if (j == -1 || b->values[j] != a->values[i]) {
01149 return FALSE;
01150 }
01151 }
01152
01153 return TRUE;
01154 }
01155
01156 static void
01157 xmms_volume_map_init (xmms_volume_map_t *vl)
01158 {
01159 vl->status = FALSE;
01160 vl->num_channels = 0;
01161 vl->names = NULL;
01162 vl->values = NULL;
01163 }
01164
01165 static void
01166 xmms_volume_map_free (xmms_volume_map_t *vl)
01167 {
01168 g_free (vl->names);
01169 g_free (vl->values);
01170
01171
01172 }
01173
01174 static void
01175 xmms_volume_map_copy (xmms_volume_map_t *src, xmms_volume_map_t *dst)
01176 {
01177 dst->num_channels = src->num_channels;
01178 dst->status = src->status;
01179
01180 if (!src->status) {
01181 g_free (dst->names);
01182 dst->names = NULL;
01183
01184 g_free (dst->values);
01185 dst->values = NULL;
01186
01187 return;
01188 }
01189
01190 dst->names = g_renew (const gchar *, dst->names, src->num_channels);
01191 dst->values = g_renew (guint, dst->values, src->num_channels);
01192
01193 memcpy (dst->names, src->names, src->num_channels * sizeof (gchar *));
01194 memcpy (dst->values, src->values, src->num_channels * sizeof (guint));
01195 }
01196
01197 static GTree *
01198 xmms_volume_map_to_dict (xmms_volume_map_t *vl)
01199 {
01200 GTree *ret;
01201 gint i;
01202
01203 ret = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
01204 NULL, (GDestroyNotify) xmmsv_unref);
01205 if (!ret) {
01206 return NULL;
01207 }
01208
01209 for (i = 0; i < vl->num_channels; i++) {
01210 xmmsv_t *val;
01211
01212 val = xmmsv_new_int (vl->values[i]);
01213 g_tree_replace (ret, (gpointer) vl->names[i], val);
01214 }
01215
01216 return ret;
01217 }
01218
01219 static gpointer
01220 xmms_output_monitor_volume_thread (gpointer data)
01221 {
01222 GTree *dict;
01223 xmms_output_t *output = data;
01224 xmms_volume_map_t old, cur;
01225
01226 if (!xmms_output_plugin_method_volume_get_available (output->plugin)) {
01227 return NULL;
01228 }
01229
01230 xmms_volume_map_init (&old);
01231 xmms_volume_map_init (&cur);
01232
01233 while (output->monitor_volume_running) {
01234 cur.num_channels = 0;
01235 cur.status = xmms_output_plugin_method_volume_get (output->plugin,
01236 output, NULL, NULL,
01237 &cur.num_channels);
01238
01239 if (cur.status) {
01240
01241 if (cur.num_channels < 1 ||
01242 cur.num_channels > VOLUME_MAX_CHANNELS) {
01243 cur.status = FALSE;
01244 } else {
01245 cur.names = g_renew (const gchar *, cur.names,
01246 cur.num_channels);
01247 cur.values = g_renew (guint, cur.values, cur.num_channels);
01248 }
01249 }
01250
01251 if (cur.status) {
01252 cur.status =
01253 xmms_output_plugin_method_volume_get (output->plugin,
01254 output, cur.names,
01255 cur.values,
01256 &cur.num_channels);
01257 }
01258
01259
01260
01261
01262 if ((cur.status ^ old.status) ||
01263 (cur.status && old.status &&
01264 !xmms_volume_map_equal (&old, &cur))) {
01265
01266 if (cur.status) {
01267 dict = xmms_volume_map_to_dict (&cur);
01268 xmms_object_emit_f (XMMS_OBJECT (output),
01269 XMMS_IPC_SIGNAL_PLAYBACK_VOLUME_CHANGED,
01270 XMMSV_TYPE_DICT, dict);
01271 g_tree_destroy (dict);
01272 } else {
01273
01274 xmms_object_emit_f (XMMS_OBJECT (output),
01275 XMMS_IPC_SIGNAL_PLAYBACK_VOLUME_CHANGED,
01276 XMMSV_TYPE_NONE);
01277 }
01278 }
01279
01280 xmms_volume_map_copy (&cur, &old);
01281
01282 g_usleep (G_USEC_PER_SEC);
01283 }
01284
01285 xmms_volume_map_free (&old);
01286 xmms_volume_map_free (&cur);
01287
01288 return NULL;
01289 }
01290
01291