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 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
00167 gchar * title = playlist_entry_get_title (playlist, entry, FALSE);
00168 if (! title)
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 {
00176 g_free (title);
00177 return;
00178 }
00179
00180 current_entry = entry;
00181 g_free (current_title);
00182 current_title = title;
00183 current_length = length;
00184
00185 if (playback_get_ready ())
00186 hook_call ("title change", NULL);
00187 }
00188
00189 gint playback_get_time (void)
00190 {
00191 g_return_val_if_fail (playing, 0);
00192
00193 if (! playback_get_ready ())
00194 return 0;
00195
00196 gint time = -1;
00197
00198 if (current_decoder->get_time != NULL)
00199 time = current_decoder->get_time (& playback_api);
00200
00201 if (time < 0)
00202 time = get_output_time ();
00203
00204 return time - time_offset;
00205 }
00206
00207 void playback_play (gint seek_time, gboolean pause)
00208 {
00209 g_return_if_fail (! playing);
00210
00211 gint playlist = playlist_get_playing ();
00212
00213 if (playlist == -1)
00214 {
00215 playlist = playlist_get_active ();
00216 playlist_set_playing (playlist);
00217 }
00218
00219 gint entry = playlist_get_position (playlist);
00220
00221 if (entry == -1)
00222 {
00223 playlist_next_song (playlist, TRUE);
00224 entry = playlist_get_position (playlist);
00225
00226 if (entry == -1)
00227 return;
00228 }
00229
00230 failed_entries = 0;
00231 playback_start (playlist, entry, seek_time, pause);
00232 }
00233
00234 void playback_pause (void)
00235 {
00236 g_return_if_fail (playing);
00237 wait_until_ready ();
00238
00239 paused = ! paused;
00240
00241 g_return_if_fail (current_decoder->pause != NULL);
00242 current_decoder->pause (& playback_api, paused);
00243
00244 if (paused)
00245 hook_call ("playback pause", NULL);
00246 else
00247 hook_call ("playback unpause", NULL);
00248 }
00249
00250 static void playback_cleanup (void)
00251 {
00252 g_return_if_fail (playing);
00253
00254 pthread_join (playback_thread_handle, NULL);
00255 playing = FALSE;
00256 playback_error = FALSE;
00257
00258 g_free (current_filename);
00259 current_filename = NULL;
00260 g_free (current_title);
00261 current_title = NULL;
00262
00263 if (ready_source)
00264 {
00265 g_source_remove (ready_source);
00266 ready_source = 0;
00267 }
00268
00269 cancel_set_tuple ();
00270 hook_dissociate ("playlist update", update_cb);
00271 }
00272
00273 static void complete_stop (void)
00274 {
00275 output_drain ();
00276 hook_call ("playback stop", NULL);
00277
00278 if (cfg.stopaftersong)
00279 {
00280 cfg.stopaftersong = FALSE;
00281 hook_call ("toggle stop after song", NULL);
00282 }
00283 }
00284
00285 void playback_stop (void)
00286 {
00287 g_return_if_fail (playing);
00288 wait_until_ready ();
00289
00290 current_decoder->stop (& playback_api);
00291 playback_cleanup ();
00292 complete_stop ();
00293
00294 if (end_source)
00295 {
00296 g_source_remove (end_source);
00297 end_source = 0;
00298 }
00299 }
00300
00301 static gboolean end_cb (void * unused)
00302 {
00303 g_return_val_if_fail (playing, FALSE);
00304
00305 hook_call ("playback end", NULL);
00306
00307 if (playback_error)
00308 failed_entries ++;
00309 else
00310 failed_entries = 0;
00311
00312 playback_cleanup ();
00313
00314 gint playlist = playlist_get_playing ();
00315
00316 while (1)
00317 {
00318 gboolean play;
00319
00320 if (cfg.no_playlist_advance)
00321 play = cfg.repeat && ! failed_entries;
00322 else if (! (play = playlist_next_song (playlist, cfg.repeat)))
00323 playlist_set_position (playlist, -1);
00324 else if (failed_entries >= 10)
00325 play = FALSE;
00326
00327 if (cfg.stopaftersong)
00328 play = FALSE;
00329
00330 if (! play)
00331 {
00332 complete_stop ();
00333 hook_call ("playlist end reached", NULL);
00334 break;
00335 }
00336
00337 if (playback_start (playlist, playlist_get_position (playlist), 0, FALSE))
00338 break;
00339
00340 failed_entries ++;
00341 }
00342
00343 end_source = 0;
00344 return FALSE;
00345 }
00346
00347 static void * playback_thread (void * unused)
00348 {
00349 gchar * real = filename_split_subtune (current_filename, NULL);
00350 VFSFile * file = vfs_fopen (real, "r");
00351 g_free (real);
00352
00353 playback_error = ! current_decoder->play (& playback_api, current_filename,
00354 file, start_time, stop_time, paused);
00355
00356 if (file != NULL)
00357 vfs_fclose (file);
00358
00359 if (! ready_flag)
00360 set_pb_ready (& playback_api);
00361
00362 end_source = g_timeout_add (0, end_cb, NULL);
00363 return NULL;
00364 }
00365
00366 static gboolean playback_start (gint playlist, gint entry, gint seek_time,
00367 gboolean pause)
00368 {
00369 g_return_val_if_fail (! playing, FALSE);
00370
00371 current_entry = entry;
00372
00373 g_free (current_filename);
00374 current_filename = playlist_entry_get_filename (playlist, entry);
00375
00376 PluginHandle * p = playlist_entry_get_decoder (playlist, entry, FALSE);
00377 current_decoder = p ? plugin_get_header (p) : NULL;
00378
00379 if (current_decoder == NULL)
00380 {
00381 gchar * error = g_strdup_printf (_("No decoder found for %s."),
00382 current_filename);
00383
00384 event_queue_with_data_free ("interface show error", error);
00385 return FALSE;
00386 }
00387
00388 current_data = NULL;
00389 current_bitrate = 0;
00390 current_samplerate = 0;
00391 current_channels = 0;
00392
00393 g_free (current_title);
00394 current_title = playlist_entry_get_title (playlist, entry, FALSE);
00395 if (! current_title)
00396 current_title = g_strdup (current_filename);
00397
00398 current_length = playlist_entry_get_length (playlist, entry, FALSE);
00399
00400 Tuple * tuple = playlist_entry_get_tuple (playlist, entry, FALSE);
00401 read_gain_from_tuple (tuple);
00402 if (tuple)
00403 tuple_free (tuple);
00404
00405 if (current_length > 0 && playlist_entry_is_segmented (playlist, entry))
00406 {
00407 time_offset = playlist_entry_get_start_time (playlist, entry);
00408 stop_time = playlist_entry_get_end_time (playlist, entry);
00409 }
00410 else
00411 {
00412 time_offset = 0;
00413 stop_time = -1;
00414 }
00415
00416 if (current_length > 0)
00417 start_time = time_offset + seek_time;
00418 else
00419 start_time = 0;
00420
00421 playing = TRUE;
00422 playback_error = FALSE;
00423 paused = pause;
00424 ready_flag = FALSE;
00425
00426 pthread_create (& playback_thread_handle, NULL, playback_thread, NULL);
00427
00428 hook_associate ("playlist update", update_cb, NULL);
00429 hook_call ("playback begin", NULL);
00430 return TRUE;
00431 }
00432
00433 gboolean playback_get_playing (void)
00434 {
00435 return playing;
00436 }
00437
00438 gboolean playback_get_paused (void)
00439 {
00440 g_return_val_if_fail (playing, FALSE);
00441 return paused;
00442 }
00443
00444 void playback_seek (gint time)
00445 {
00446 g_return_if_fail (playing);
00447 wait_until_ready ();
00448
00449 if (current_decoder->mseek == NULL || playback_get_length () < 1)
00450 return;
00451
00452 current_decoder->mseek (& playback_api, time_offset + CLAMP (time, 0,
00453 current_length));
00454
00455 hook_call ("playback seek", NULL);
00456 }
00457
00458 static void set_data (InputPlayback * p, void * data)
00459 {
00460 g_return_if_fail (playing);
00461 current_data = data;
00462 }
00463
00464 static void * get_data (InputPlayback * p)
00465 {
00466 g_return_val_if_fail (playing, NULL);
00467 return current_data;
00468 }
00469
00470 static void set_params (InputPlayback * p, gint bitrate, gint samplerate,
00471 gint channels)
00472 {
00473 g_return_if_fail (playing);
00474
00475 current_bitrate = bitrate;
00476 current_samplerate = samplerate;
00477 current_channels = channels;
00478
00479 event_queue ("info change", NULL);
00480 }
00481
00482 static gboolean set_tuple_cb (void * unused)
00483 {
00484 g_return_val_if_fail (playing, FALSE);
00485 pthread_mutex_lock (& ready_mutex);
00486
00487 gint playlist = playlist_get_playing ();
00488 playlist_entry_set_tuple (playlist, playlist_get_position (playlist),
00489 tuple_to_be_set);
00490 set_tuple_source = 0;
00491 tuple_to_be_set = NULL;
00492
00493 pthread_mutex_unlock (& ready_mutex);
00494 return FALSE;
00495 }
00496
00497 static void set_tuple (InputPlayback * p, Tuple * tuple)
00498 {
00499 g_return_if_fail (playing);
00500 pthread_mutex_lock (& ready_mutex);
00501
00502 cancel_set_tuple ();
00503 set_tuple_source = g_timeout_add (0, set_tuple_cb, NULL);
00504 tuple_to_be_set = tuple;
00505
00506 read_gain_from_tuple (tuple);
00507 pthread_mutex_unlock (& ready_mutex);
00508 }
00509
00510 static void set_gain_from_playlist (InputPlayback * p)
00511 {
00512 g_return_if_fail (playing);
00513 p->output->set_replaygain_info (& gain_from_playlist);
00514 }
00515
00516 static InputPlayback playback_api = {
00517 .output = & output_api,
00518 .set_data = set_data,
00519 .get_data = get_data,
00520 .set_pb_ready = set_pb_ready,
00521 .set_params = set_params,
00522 .set_tuple = set_tuple,
00523 .set_gain_from_playlist = set_gain_from_playlist,
00524 };
00525
00526 gchar * playback_get_title (void)
00527 {
00528 g_return_val_if_fail (playing, NULL);
00529
00530 if (! playback_get_ready ())
00531 return g_strdup (_("Buffering ..."));
00532
00533 gchar s[128];
00534
00535 if (current_length)
00536 {
00537 gint len = current_length / 1000;
00538
00539 if (len < 3600)
00540 snprintf (s, sizeof s, cfg.leading_zero ? " (%02d:%02d)" :
00541 " (%d:%02d)", len / 60, len % 60);
00542 else
00543 snprintf (s, sizeof s, " (%d:%02d:%02d)", len / 3600, (len / 60) %
00544 60, len % 60);
00545 }
00546 else
00547 s[0] = 0;
00548
00549 if (cfg.show_numbers_in_pl)
00550 return g_strdup_printf ("%d. %s%s", 1 + playlist_get_position
00551 (playlist_get_playing ()), current_title, s);
00552
00553 return g_strdup_printf ("%s%s", current_title, s);
00554 }
00555
00556 gint playback_get_length (void)
00557 {
00558 g_return_val_if_fail (playing, 0);
00559 return current_length;
00560 }
00561
00562 void playback_get_info (gint * bitrate, gint * samplerate, gint * channels)
00563 {
00564 g_return_if_fail (playing);
00565 * bitrate = current_bitrate;
00566 * samplerate = current_samplerate;
00567 * channels = current_channels;
00568 }
00569
00570 void playback_get_volume (gint * l, gint * r)
00571 {
00572 if (playing && current_decoder->get_volume != NULL &&
00573 current_decoder->get_volume (l, r))
00574 return;
00575
00576 output_get_volume (l, r);
00577 }
00578
00579 void playback_set_volume(gint l, gint r)
00580 {
00581 gint h_vol[2] = {l, r};
00582
00583 hook_call ("volume set", h_vol);
00584
00585 if (playing && current_decoder->set_volume != NULL &&
00586 current_decoder->set_volume (l, r))
00587 return;
00588
00589 output_set_volume (l, r);
00590 }