00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <glib.h>
00023 #include <pthread.h>
00024
00025 #include <libaudcore/audstrings.h>
00026 #include <libaudcore/eventqueue.h>
00027 #include <libaudcore/hook.h>
00028
00029 #include "config.h"
00030 #include "i18n.h"
00031 #include "interface.h"
00032 #include "misc.h"
00033 #include "output.h"
00034 #include "playback.h"
00035 #include "playlist.h"
00036
00037 static void playback_start (gint playlist, gint entry, gint seek_time, gboolean pause);
00038
00039 static InputPlayback playback_api;
00040
00041 static gboolean playing = FALSE;
00042 static gboolean playback_error;
00043 static gint failed_entries;
00044
00045 static gchar * current_filename;
00046
00047 static gint current_entry;
00048 static gchar * current_title;
00049 static gint current_length;
00050
00051 static InputPlugin * current_decoder;
00052 static void * current_data;
00053 static gint current_bitrate, current_samplerate, current_channels;
00054
00055 static ReplayGainInfo gain_from_playlist;
00056
00057 static gint time_offset, initial_seek;
00058 static gboolean paused;
00059
00060 static pthread_t playback_thread_handle;
00061 static gint end_source = 0;
00062
00063 static pthread_mutex_t ready_mutex = PTHREAD_MUTEX_INITIALIZER;
00064 static pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;
00065 static gboolean ready_flag;
00066
00067
00068 static void read_gain_from_tuple (const Tuple * tuple)
00069 {
00070 memset (& gain_from_playlist, 0, sizeof gain_from_playlist);
00071
00072 if (tuple == NULL)
00073 return;
00074
00075 gint album_gain = tuple_get_int (tuple, FIELD_GAIN_ALBUM_GAIN, NULL);
00076 gint album_peak = tuple_get_int (tuple, FIELD_GAIN_ALBUM_PEAK, NULL);
00077 gint track_gain = tuple_get_int (tuple, FIELD_GAIN_TRACK_GAIN, NULL);
00078 gint track_peak = tuple_get_int (tuple, FIELD_GAIN_TRACK_PEAK, NULL);
00079 gint gain_unit = tuple_get_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL);
00080 gint peak_unit = tuple_get_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL);
00081
00082 if (gain_unit)
00083 {
00084 gain_from_playlist.album_gain = album_gain / (gfloat) gain_unit;
00085 gain_from_playlist.track_gain = track_gain / (gfloat) gain_unit;
00086 }
00087
00088 if (peak_unit)
00089 {
00090 gain_from_playlist.album_peak = album_peak / (gfloat) peak_unit;
00091 gain_from_playlist.track_peak = track_peak / (gfloat) peak_unit;
00092 }
00093 }
00094
00095 static gboolean update_from_playlist (void)
00096 {
00097 gint entry = playback_entry_get_position ();
00098 gchar * title = playback_entry_get_title ();
00099 gint length = playback_entry_get_length ();
00100
00101 if (entry == current_entry && ! g_strcmp0 (title, current_title) && length == current_length)
00102 {
00103 g_free (title);
00104 return FALSE;
00105 }
00106
00107 current_entry = entry;
00108 g_free (current_title);
00109 current_title = title;
00110 current_length = length;
00111 return TRUE;
00112 }
00113
00114 gboolean playback_get_ready (void)
00115 {
00116 g_return_val_if_fail (playing, FALSE);
00117 pthread_mutex_lock (& ready_mutex);
00118 gboolean ready = ready_flag;
00119 pthread_mutex_unlock (& ready_mutex);
00120 return ready;
00121 }
00122
00123 static void set_pb_ready (InputPlayback * p)
00124 {
00125 g_return_if_fail (playing);
00126 pthread_mutex_lock (& ready_mutex);
00127
00128 update_from_playlist ();
00129 ready_flag = TRUE;
00130
00131 pthread_cond_signal (& ready_cond);
00132 pthread_mutex_unlock (& ready_mutex);
00133
00134 event_queue ("playback ready", NULL);
00135 }
00136
00137 static void wait_until_ready (void)
00138 {
00139 g_return_if_fail (playing);
00140 pthread_mutex_lock (& ready_mutex);
00141
00142 while (! ready_flag)
00143 pthread_cond_wait (& ready_cond, & ready_mutex);
00144
00145 pthread_mutex_unlock (& ready_mutex);
00146 }
00147
00148 static void update_cb (void * hook_data, void * user_data)
00149 {
00150 g_return_if_fail (playing);
00151
00152 if (GPOINTER_TO_INT (hook_data) < PLAYLIST_UPDATE_METADATA || ! playback_get_ready ())
00153 return;
00154
00155 if (update_from_playlist ())
00156 hook_call ("title change", NULL);
00157 }
00158
00159 gint playback_get_time (void)
00160 {
00161 g_return_val_if_fail (playing, 0);
00162 wait_until_ready ();
00163
00164 gint time = -1;
00165
00166 if (current_decoder && current_decoder->get_time)
00167 time = current_decoder->get_time (& playback_api);
00168
00169 if (time < 0)
00170 time = get_output_time ();
00171
00172 return time - time_offset;
00173 }
00174
00175 void playback_play (gint seek_time, gboolean pause)
00176 {
00177 g_return_if_fail (! playing);
00178
00179 gint playlist = playlist_get_playing ();
00180
00181 if (playlist == -1)
00182 {
00183 playlist = playlist_get_active ();
00184 playlist_set_playing (playlist);
00185 }
00186
00187 gint entry = playlist_get_position (playlist);
00188
00189 if (entry == -1)
00190 {
00191 playlist_next_song (playlist, TRUE);
00192 entry = playlist_get_position (playlist);
00193
00194 if (entry == -1)
00195 return;
00196 }
00197
00198 failed_entries = 0;
00199 playback_start (playlist, entry, seek_time, pause);
00200 }
00201
00202 void playback_pause (void)
00203 {
00204 g_return_if_fail (playing);
00205 wait_until_ready ();
00206
00207 if (! current_decoder || ! current_decoder->pause)
00208 return;
00209
00210 paused = ! paused;
00211 current_decoder->pause (& playback_api, paused);
00212
00213 if (paused)
00214 hook_call ("playback pause", NULL);
00215 else
00216 hook_call ("playback unpause", NULL);
00217 }
00218
00219 static void playback_cleanup (void)
00220 {
00221 g_return_if_fail (playing);
00222
00223 pthread_join (playback_thread_handle, NULL);
00224 playing = FALSE;
00225
00226 event_queue_cancel ("playback ready", NULL);
00227 event_queue_cancel ("info change", NULL);
00228
00229 if (end_source)
00230 {
00231 g_source_remove (end_source);
00232 end_source = 0;
00233 }
00234
00235 g_free (current_filename);
00236 current_filename = NULL;
00237 g_free (current_title);
00238 current_title = NULL;
00239
00240 hook_dissociate ("playlist update", update_cb);
00241 }
00242
00243 static void complete_stop (void)
00244 {
00245 output_drain ();
00246 hook_call ("playback stop", NULL);
00247 set_bool (NULL, "stop_after_current_song", FALSE);
00248 }
00249
00250 void playback_stop (void)
00251 {
00252 g_return_if_fail (playing);
00253 wait_until_ready ();
00254
00255 if (current_decoder)
00256 current_decoder->stop (& playback_api);
00257
00258 playback_cleanup ();
00259 complete_stop ();
00260 }
00261
00262 static gboolean end_cb (void * unused)
00263 {
00264 g_return_val_if_fail (playing, FALSE);
00265
00266 hook_call ("playback end", NULL);
00267
00268 if (playback_error)
00269 failed_entries ++;
00270 else
00271 failed_entries = 0;
00272
00273 playback_cleanup ();
00274
00275 gint playlist = playlist_get_playing ();
00276 gboolean play;
00277
00278 if (get_bool (NULL, "no_playlist_advance"))
00279 play = get_bool (NULL, "repeat") && ! failed_entries;
00280 else if (! (play = playlist_next_song (playlist, get_bool (NULL, "repeat"))))
00281 playlist_set_position (playlist, -1);
00282 else if (failed_entries >= 10)
00283 play = FALSE;
00284
00285 if (get_bool (NULL, "stop_after_current_song"))
00286 play = FALSE;
00287
00288 if (play)
00289 playback_start (playlist, playlist_get_position (playlist), 0, FALSE);
00290 else
00291 {
00292 complete_stop ();
00293 hook_call ("playlist end reached", NULL);
00294 }
00295
00296 return FALSE;
00297 }
00298
00299 static void * playback_thread (void * unused)
00300 {
00301 PluginHandle * p = playback_entry_get_decoder ();
00302 current_decoder = p ? plugin_get_header (p) : NULL;
00303
00304 if (! current_decoder)
00305 {
00306 gchar * error = g_strdup_printf (_("No decoder found for %s."),
00307 current_filename);
00308 event_queue_with_data_free ("interface show error", error);
00309 playback_error = TRUE;
00310 goto DONE;
00311 }
00312
00313 current_data = NULL;
00314 current_bitrate = 0;
00315 current_samplerate = 0;
00316 current_channels = 0;
00317
00318 Tuple * tuple = playback_entry_get_tuple ();
00319 read_gain_from_tuple (tuple);
00320 if (tuple)
00321 tuple_free (tuple);
00322
00323 gchar * real = filename_split_subtune (current_filename, NULL);
00324 VFSFile * file = vfs_fopen (real, "r");
00325 g_free (real);
00326
00327 time_offset = playback_entry_get_start_time ();
00328 playback_error = ! current_decoder->play (& playback_api, current_filename,
00329 file, time_offset + initial_seek, playback_entry_get_end_time (), paused);
00330
00331 if (file)
00332 vfs_fclose (file);
00333
00334 DONE:
00335 if (! ready_flag)
00336 set_pb_ready (& playback_api);
00337
00338 end_source = g_timeout_add (0, end_cb, NULL);
00339 return NULL;
00340 }
00341
00342 static void playback_start (gint playlist, gint entry, gint seek_time, gboolean pause)
00343 {
00344 g_return_if_fail (! playing);
00345
00346 current_filename = playlist_entry_get_filename (playlist, entry);
00347 g_return_if_fail (current_filename);
00348
00349 playing = TRUE;
00350 playback_error = FALSE;
00351 ready_flag = FALSE;
00352
00353 current_entry = -1;
00354 current_title = NULL;
00355 current_length = 0;
00356
00357 initial_seek = seek_time;
00358 paused = pause;
00359
00360 hook_associate ("playlist update", update_cb, NULL);
00361 pthread_create (& playback_thread_handle, NULL, playback_thread, NULL);
00362
00363 hook_call ("playback begin", NULL);
00364 }
00365
00366 gboolean playback_get_playing (void)
00367 {
00368 return playing;
00369 }
00370
00371 gboolean playback_get_paused (void)
00372 {
00373 g_return_val_if_fail (playing, FALSE);
00374 return paused;
00375 }
00376
00377 void playback_seek (gint time)
00378 {
00379 g_return_if_fail (playing);
00380 wait_until_ready ();
00381
00382 if (! current_decoder || ! current_decoder->mseek || current_length < 1)
00383 return;
00384
00385 current_decoder->mseek (& playback_api, time_offset + CLAMP (time, 0,
00386 current_length));
00387
00388 hook_call ("playback seek", NULL);
00389 }
00390
00391 static void set_data (InputPlayback * p, void * data)
00392 {
00393 g_return_if_fail (playing);
00394 current_data = data;
00395 }
00396
00397 static void * get_data (InputPlayback * p)
00398 {
00399 g_return_val_if_fail (playing, NULL);
00400 return current_data;
00401 }
00402
00403 static void set_params (InputPlayback * p, gint bitrate, gint samplerate,
00404 gint channels)
00405 {
00406 g_return_if_fail (playing);
00407
00408 current_bitrate = bitrate;
00409 current_samplerate = samplerate;
00410 current_channels = channels;
00411
00412 if (playback_get_ready ())
00413 event_queue ("info change", NULL);
00414 }
00415
00416 static void set_tuple (InputPlayback * p, Tuple * tuple)
00417 {
00418 g_return_if_fail (playing);
00419 read_gain_from_tuple (tuple);
00420 playback_entry_set_tuple (tuple);
00421 }
00422
00423 static void set_gain_from_playlist (InputPlayback * p)
00424 {
00425 g_return_if_fail (playing);
00426 p->output->set_replaygain_info (& gain_from_playlist);
00427 }
00428
00429 static InputPlayback playback_api = {
00430 .output = & output_api,
00431 .set_data = set_data,
00432 .get_data = get_data,
00433 .set_pb_ready = set_pb_ready,
00434 .set_params = set_params,
00435 .set_tuple = set_tuple,
00436 .set_gain_from_playlist = set_gain_from_playlist,
00437 };
00438
00439 gchar * playback_get_title (void)
00440 {
00441 g_return_val_if_fail (playing, NULL);
00442 wait_until_ready ();
00443
00444 gchar s[32];
00445
00446 if (current_length)
00447 {
00448 gint len = current_length / 1000;
00449
00450 if (len < 3600)
00451 snprintf (s, sizeof s, get_bool (NULL, "leading_zero") ?
00452 " (%02d:%02d)" : " (%d:%02d)", len / 60, len % 60);
00453 else
00454 snprintf (s, sizeof s, " (%d:%02d:%02d)", len / 3600, (len / 60) %
00455 60, len % 60);
00456 }
00457 else
00458 s[0] = 0;
00459
00460 if (get_bool (NULL, "show_numbers_in_pl"))
00461 return g_strdup_printf ("%d. %s%s", 1 + playlist_get_position
00462 (playlist_get_playing ()), current_title, s);
00463
00464 return g_strdup_printf ("%s%s", current_title, s);
00465 }
00466
00467 gint playback_get_length (void)
00468 {
00469 g_return_val_if_fail (playing, 0);
00470 wait_until_ready ();
00471
00472 return current_length;
00473 }
00474
00475 void playback_get_info (gint * bitrate, gint * samplerate, gint * channels)
00476 {
00477 g_return_if_fail (playing);
00478 wait_until_ready ();
00479
00480 * bitrate = current_bitrate;
00481 * samplerate = current_samplerate;
00482 * channels = current_channels;
00483 }
00484
00485 void playback_get_volume (gint * l, gint * r)
00486 {
00487 if (playing && playback_get_ready () && current_decoder &&
00488 current_decoder->get_volume && current_decoder->get_volume (l, r))
00489 return;
00490
00491 output_get_volume (l, r);
00492 }
00493
00494 void playback_set_volume (gint l, gint r)
00495 {
00496 gint h_vol[2] = {l, r};
00497
00498 hook_call ("volume set", h_vol);
00499
00500 if (playing && playback_get_ready () && current_decoder &&
00501 current_decoder->set_volume && current_decoder->set_volume (l, r))
00502 return;
00503
00504 output_set_volume (l, r);
00505 }