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