Merge branch 'v0.16.x'
Conflicts: configure.ac src/player_control.c src/player_thread.c src/playlist_song.c
This commit is contained in:
commit
5c0576ca55
@ -872,6 +872,15 @@ FILTER_SRC = \
|
|||||||
src/filter/volume_filter_plugin.c
|
src/filter/volume_filter_plugin.c
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# systemd unit
|
||||||
|
#
|
||||||
|
|
||||||
|
if HAVE_SYSTEMD
|
||||||
|
systemdsystemunit_DATA = \
|
||||||
|
mpd.service
|
||||||
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
# Sparse code analysis
|
# Sparse code analysis
|
||||||
#
|
#
|
||||||
|
7
NEWS
7
NEWS
@ -37,7 +37,14 @@ ver 0.16.5 (2010/??/??)
|
|||||||
- ffmpeg: higher precision timestamps
|
- ffmpeg: higher precision timestamps
|
||||||
- ffmpeg: don't require key frame for seeking
|
- ffmpeg: don't require key frame for seeking
|
||||||
- fix CUE track seeking
|
- fix CUE track seeking
|
||||||
|
* player:
|
||||||
|
- make seeking to CUE track more reliable
|
||||||
|
- the "seek" command works when MPD is stopped
|
||||||
|
- restore song position from state file (bug fix)
|
||||||
|
- fix crash that sometimes occurred when audio device fails on startup
|
||||||
|
- fix absolute path support in playlists
|
||||||
* WIN32: close sockets properly
|
* WIN32: close sockets properly
|
||||||
|
* install systemd service file if systemd is available
|
||||||
|
|
||||||
|
|
||||||
ver 0.16.4 (2011/09/01)
|
ver 0.16.4 (2011/09/01)
|
||||||
|
@ -34,6 +34,13 @@ AM_CONDITIONAL(HAVE_CXX, test x$HAVE_CXX = xyes)
|
|||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
AC_PROG_MAKE_SET
|
AC_PROG_MAKE_SET
|
||||||
PKG_PROG_PKG_CONFIG
|
PKG_PROG_PKG_CONFIG
|
||||||
|
AC_ARG_WITH([systemdsystemunitdir],
|
||||||
|
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
|
||||||
|
[], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
|
||||||
|
if test "x$with_systemdsystemunitdir" != xno; then
|
||||||
|
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
|
||||||
|
|
||||||
dnl ---------------------------------------------------------------------------
|
dnl ---------------------------------------------------------------------------
|
||||||
dnl Declare Variables
|
dnl Declare Variables
|
||||||
@ -1617,5 +1624,6 @@ dnl Generate files
|
|||||||
dnl ---------------------------------------------------------------------------
|
dnl ---------------------------------------------------------------------------
|
||||||
AC_OUTPUT(Makefile)
|
AC_OUTPUT(Makefile)
|
||||||
AC_OUTPUT(doc/doxygen.conf)
|
AC_OUTPUT(doc/doxygen.conf)
|
||||||
|
AC_OUTPUT(mpd.service)
|
||||||
|
|
||||||
echo 'MPD is ready for compilation, type "make" to begin.'
|
echo 'MPD is ready for compilation, type "make" to begin.'
|
||||||
|
9
mpd.service.in
Normal file
9
mpd.service.in
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Music Player Daemon
|
||||||
|
After=sound.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=@prefix@/bin/mpd --no-daemon
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -76,6 +76,40 @@ decoder_initialized(struct decoder *decoder,
|
|||||||
&af_string));
|
&af_string));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if we need an "initial seek". If so, then the initial seek
|
||||||
|
* is prepared, and the function returns true.
|
||||||
|
*/
|
||||||
|
G_GNUC_PURE
|
||||||
|
static bool
|
||||||
|
decoder_prepare_initial_seek(struct decoder *decoder)
|
||||||
|
{
|
||||||
|
const struct decoder_control *dc = decoder->dc;
|
||||||
|
assert(dc->pipe != NULL);
|
||||||
|
|
||||||
|
if (decoder->initial_seek_running)
|
||||||
|
/* initial seek has already begun - override any other
|
||||||
|
command */
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (decoder->initial_seek_pending) {
|
||||||
|
if (dc->command == DECODE_COMMAND_NONE) {
|
||||||
|
/* begin initial seek */
|
||||||
|
|
||||||
|
decoder->initial_seek_pending = false;
|
||||||
|
decoder->initial_seek_running = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip initial seek when there's another command
|
||||||
|
(e.g. STOP) */
|
||||||
|
|
||||||
|
decoder->initial_seek_pending = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current decoder command. May return a "virtual"
|
* Returns the current decoder command. May return a "virtual"
|
||||||
* synthesized command, e.g. to seek to the beginning of the CUE
|
* synthesized command, e.g. to seek to the beginning of the CUE
|
||||||
@ -88,19 +122,9 @@ decoder_get_virtual_command(struct decoder *decoder)
|
|||||||
const struct decoder_control *dc = decoder->dc;
|
const struct decoder_control *dc = decoder->dc;
|
||||||
assert(dc->pipe != NULL);
|
assert(dc->pipe != NULL);
|
||||||
|
|
||||||
if (decoder->initial_seek_running)
|
if (decoder_prepare_initial_seek(decoder))
|
||||||
return DECODE_COMMAND_SEEK;
|
return DECODE_COMMAND_SEEK;
|
||||||
|
|
||||||
if (decoder->initial_seek_pending) {
|
|
||||||
if (dc->command == DECODE_COMMAND_NONE) {
|
|
||||||
decoder->initial_seek_pending = false;
|
|
||||||
decoder->initial_seek_running = true;
|
|
||||||
return DECODE_COMMAND_SEEK;
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder->initial_seek_pending = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dc->command;
|
return dc->command;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +154,7 @@ decoder_command_finished(struct decoder *decoder)
|
|||||||
assert(music_pipe_empty(dc->pipe));
|
assert(music_pipe_empty(dc->pipe));
|
||||||
|
|
||||||
decoder->initial_seek_running = false;
|
decoder->initial_seek_running = false;
|
||||||
decoder->timestamp = dc->song->start_ms / 1000.;
|
decoder->timestamp = dc->start_ms / 1000.;
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -162,7 +186,7 @@ double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
|
|||||||
assert(dc->pipe != NULL);
|
assert(dc->pipe != NULL);
|
||||||
|
|
||||||
if (decoder->initial_seek_running)
|
if (decoder->initial_seek_running)
|
||||||
return dc->song->start_ms / 1000.;
|
return dc->start_ms / 1000.;
|
||||||
|
|
||||||
assert(dc->command == DECODE_COMMAND_SEEK);
|
assert(dc->command == DECODE_COMMAND_SEEK);
|
||||||
|
|
||||||
@ -177,10 +201,12 @@ void decoder_seek_error(struct decoder * decoder)
|
|||||||
|
|
||||||
assert(dc->pipe != NULL);
|
assert(dc->pipe != NULL);
|
||||||
|
|
||||||
if (decoder->initial_seek_running)
|
if (decoder->initial_seek_running) {
|
||||||
/* d'oh, we can't seek to the sub-song start position,
|
/* d'oh, we can't seek to the sub-song start position,
|
||||||
what now? - no idea, ignoring the problem for now. */
|
what now? - no idea, ignoring the problem for now. */
|
||||||
|
decoder->initial_seek_running = false;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assert(dc->command == DECODE_COMMAND_SEEK);
|
assert(dc->command == DECODE_COMMAND_SEEK);
|
||||||
|
|
||||||
@ -424,8 +450,8 @@ decoder_data(struct decoder *decoder,
|
|||||||
decoder->timestamp += (double)nbytes /
|
decoder->timestamp += (double)nbytes /
|
||||||
audio_format_time_to_size(&dc->out_audio_format);
|
audio_format_time_to_size(&dc->out_audio_format);
|
||||||
|
|
||||||
if (dc->song->end_ms > 0 &&
|
if (dc->end_ms > 0 &&
|
||||||
decoder->timestamp >= dc->song->end_ms / 1000.0)
|
decoder->timestamp >= dc->end_ms / 1000.0)
|
||||||
/* the end of this range has been reached:
|
/* the end of this range has been reached:
|
||||||
stop decoding */
|
stop decoding */
|
||||||
return DECODE_COMMAND_STOP;
|
return DECODE_COMMAND_STOP;
|
||||||
@ -455,6 +481,14 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
|
|||||||
|
|
||||||
update_stream_tag(decoder, is);
|
update_stream_tag(decoder, is);
|
||||||
|
|
||||||
|
/* check if we're seeking */
|
||||||
|
|
||||||
|
if (decoder_prepare_initial_seek(decoder))
|
||||||
|
/* during initial seek, no music chunk must be created
|
||||||
|
until seeking is finished; skip the rest of the
|
||||||
|
function here */
|
||||||
|
return DECODE_COMMAND_SEEK;
|
||||||
|
|
||||||
/* send tag to music pipe */
|
/* send tag to music pipe */
|
||||||
|
|
||||||
if (decoder->stream_tag != NULL) {
|
if (decoder->stream_tag != NULL) {
|
||||||
@ -468,9 +502,6 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
|
|||||||
/* send only the decoder tag */
|
/* send only the decoder tag */
|
||||||
cmd = do_send_tag(decoder, tag);
|
cmd = do_send_tag(decoder, tag);
|
||||||
|
|
||||||
if (cmd == DECODE_COMMAND_NONE)
|
|
||||||
cmd = decoder_get_virtual_command(decoder);
|
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,7 @@ dc_command_async(struct decoder_control *dc, enum decoder_command cmd)
|
|||||||
|
|
||||||
void
|
void
|
||||||
dc_start(struct decoder_control *dc, struct song *song,
|
dc_start(struct decoder_control *dc, struct song *song,
|
||||||
|
unsigned start_ms, unsigned end_ms,
|
||||||
struct music_buffer *buffer, struct music_pipe *pipe)
|
struct music_buffer *buffer, struct music_pipe *pipe)
|
||||||
{
|
{
|
||||||
assert(song != NULL);
|
assert(song != NULL);
|
||||||
@ -104,6 +105,8 @@ dc_start(struct decoder_control *dc, struct song *song,
|
|||||||
assert(music_pipe_empty(pipe));
|
assert(music_pipe_empty(pipe));
|
||||||
|
|
||||||
dc->song = song;
|
dc->song = song;
|
||||||
|
dc->start_ms = start_ms;
|
||||||
|
dc->end_ms = end_ms;
|
||||||
dc->buffer = buffer;
|
dc->buffer = buffer;
|
||||||
dc->pipe = pipe;
|
dc->pipe = pipe;
|
||||||
dc_command(dc, DECODE_COMMAND_START);
|
dc_command(dc, DECODE_COMMAND_START);
|
||||||
|
@ -85,6 +85,23 @@ struct decoder_control {
|
|||||||
*/
|
*/
|
||||||
const struct song *song;
|
const struct song *song;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initial seek position (in milliseconds), e.g. to the
|
||||||
|
* start of a sub-track described by a CUE file.
|
||||||
|
*
|
||||||
|
* This attribute is set by dc_start().
|
||||||
|
*/
|
||||||
|
unsigned start_ms;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoder will stop when it reaches this position (in
|
||||||
|
* milliseconds). 0 means don't stop before the end of the
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* This attribute is set by dc_start().
|
||||||
|
*/
|
||||||
|
unsigned end_ms;
|
||||||
|
|
||||||
float total_time;
|
float total_time;
|
||||||
|
|
||||||
/** the #music_chunk allocator */
|
/** the #music_chunk allocator */
|
||||||
@ -229,11 +246,14 @@ decoder_current_song(const struct decoder_control *dc)
|
|||||||
*
|
*
|
||||||
* @param the decoder
|
* @param the decoder
|
||||||
* @param song the song to be decoded
|
* @param song the song to be decoded
|
||||||
|
* @param start_ms see #decoder_control
|
||||||
|
* @param end_ms see #decoder_control
|
||||||
* @param pipe the pipe which receives the decoded chunks (owned by
|
* @param pipe the pipe which receives the decoded chunks (owned by
|
||||||
* the caller)
|
* the caller)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
dc_start(struct decoder_control *dc, struct song *song,
|
dc_start(struct decoder_control *dc, struct song *song,
|
||||||
|
unsigned start_ms, unsigned end_ms,
|
||||||
struct music_buffer *buffer, struct music_pipe *pipe);
|
struct music_buffer *buffer, struct music_pipe *pipe);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -380,7 +380,7 @@ decoder_run_song(struct decoder_control *dc,
|
|||||||
{
|
{
|
||||||
struct decoder decoder = {
|
struct decoder decoder = {
|
||||||
.dc = dc,
|
.dc = dc,
|
||||||
.initial_seek_pending = song->start_ms > 0,
|
.initial_seek_pending = dc->start_ms > 0,
|
||||||
.initial_seek_running = false,
|
.initial_seek_running = false,
|
||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -126,9 +126,6 @@ audio_output_disable(struct audio_output *ao)
|
|||||||
ao_lock_command(ao, AO_COMMAND_DISABLE);
|
ao_lock_command(ao, AO_COMMAND_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
audio_output_close_locked(struct audio_output *ao);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object must be locked (and unlocked) by the caller.
|
* Object must be locked (and unlocked) by the caller.
|
||||||
*/
|
*/
|
||||||
|
@ -319,9 +319,6 @@ pc_seek(struct player_control *pc, struct song *song, float seek_time)
|
|||||||
{
|
{
|
||||||
assert(song != NULL);
|
assert(song != NULL);
|
||||||
|
|
||||||
if (pc->state == PLAYER_STATE_STOP)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
player_lock(pc);
|
player_lock(pc);
|
||||||
pc->next_song = song;
|
pc->next_song = song;
|
||||||
pc->seek_where = seek_time;
|
pc->seek_where = seek_time;
|
||||||
|
@ -75,6 +75,14 @@ struct player {
|
|||||||
*/
|
*/
|
||||||
bool queued;
|
bool queued;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was any audio output opened successfully? It might have
|
||||||
|
* failed meanwhile, but was not explicitly closed by the
|
||||||
|
* player thread. When this flag is unset, some output
|
||||||
|
* methods must not be called.
|
||||||
|
*/
|
||||||
|
bool output_open;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the song currently being played
|
* the song currently being played
|
||||||
*/
|
*/
|
||||||
@ -150,7 +158,13 @@ player_dc_start(struct player *player, struct music_pipe *pipe)
|
|||||||
assert(player->queued || pc->command == PLAYER_COMMAND_SEEK);
|
assert(player->queued || pc->command == PLAYER_COMMAND_SEEK);
|
||||||
assert(pc->next_song != NULL);
|
assert(pc->next_song != NULL);
|
||||||
|
|
||||||
dc_start(dc, pc->next_song, player_buffer, pipe);
|
unsigned start_ms = pc->next_song->start_ms;
|
||||||
|
if (pc->command == PLAYER_COMMAND_SEEK)
|
||||||
|
start_ms += (unsigned)(pc->seek_where * 1000);
|
||||||
|
|
||||||
|
dc_start(dc, pc->next_song,
|
||||||
|
start_ms, pc->next_song->end_ms,
|
||||||
|
player_buffer, pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -276,6 +290,46 @@ real_song_duration(const struct song *song, double decoder_duration)
|
|||||||
return decoder_duration - song->start_ms / 1000.0;
|
return decoder_duration - song->start_ms / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for audio_output_all_open(). Upon failure, it pauses the
|
||||||
|
* player.
|
||||||
|
*
|
||||||
|
* @return true on success
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
player_open_output(struct player *player)
|
||||||
|
{
|
||||||
|
struct player_control *pc = player->pc;
|
||||||
|
|
||||||
|
assert(audio_format_defined(&player->play_audio_format));
|
||||||
|
assert(pc->state == PLAYER_STATE_PLAY ||
|
||||||
|
pc->state == PLAYER_STATE_PAUSE);
|
||||||
|
|
||||||
|
if (audio_output_all_open(&player->play_audio_format, player_buffer)) {
|
||||||
|
player->output_open = true;
|
||||||
|
player->paused = false;
|
||||||
|
|
||||||
|
player_lock(pc);
|
||||||
|
pc->state = PLAYER_STATE_PLAY;
|
||||||
|
player_unlock(pc);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
player->output_open = false;
|
||||||
|
|
||||||
|
/* pause: the user may resume playback as soon as an
|
||||||
|
audio output becomes available */
|
||||||
|
player->paused = true;
|
||||||
|
|
||||||
|
player_lock(pc);
|
||||||
|
pc->error = PLAYER_ERROR_AUDIO;
|
||||||
|
pc->state = PLAYER_STATE_PAUSE;
|
||||||
|
player_unlock(pc);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The decoder has acknowledged the "START" command (see
|
* The decoder has acknowledged the "START" command (see
|
||||||
* player_wait_for_decoder()). This function checks if the decoder
|
* player_wait_for_decoder()). This function checks if the decoder
|
||||||
@ -308,7 +362,7 @@ player_check_decoder_startup(struct player *player)
|
|||||||
|
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
|
|
||||||
if (audio_format_defined(&player->play_audio_format) &&
|
if (player->output_open &&
|
||||||
!audio_output_all_wait(pc, 1))
|
!audio_output_all_wait(pc, 1))
|
||||||
/* the output devices havn't finished playing
|
/* the output devices havn't finished playing
|
||||||
all chunks yet - wait for that */
|
all chunks yet - wait for that */
|
||||||
@ -322,23 +376,12 @@ player_check_decoder_startup(struct player *player)
|
|||||||
player->play_audio_format = dc->out_audio_format;
|
player->play_audio_format = dc->out_audio_format;
|
||||||
player->decoder_starting = false;
|
player->decoder_starting = false;
|
||||||
|
|
||||||
if (!player->paused &&
|
if (!player->paused && !player_open_output(player)) {
|
||||||
!audio_output_all_open(&dc->out_audio_format,
|
|
||||||
player_buffer)) {
|
|
||||||
char *uri = song_get_uri(dc->song);
|
char *uri = song_get_uri(dc->song);
|
||||||
g_warning("problems opening audio device "
|
g_warning("problems opening audio device "
|
||||||
"while playing \"%s\"", uri);
|
"while playing \"%s\"", uri);
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
|
|
||||||
player_lock(pc);
|
|
||||||
pc->error = PLAYER_ERROR_AUDIO;
|
|
||||||
|
|
||||||
/* pause: the user may resume playback as soon
|
|
||||||
as an audio output becomes available */
|
|
||||||
pc->state = PLAYER_STATE_PAUSE;
|
|
||||||
player_unlock(pc);
|
|
||||||
|
|
||||||
player->paused = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,6 +406,7 @@ player_check_decoder_startup(struct player *player)
|
|||||||
static bool
|
static bool
|
||||||
player_send_silence(struct player *player)
|
player_send_silence(struct player *player)
|
||||||
{
|
{
|
||||||
|
assert(player->output_open);
|
||||||
assert(audio_format_defined(&player->play_audio_format));
|
assert(audio_format_defined(&player->play_audio_format));
|
||||||
|
|
||||||
struct music_chunk *chunk = music_buffer_allocate(player_buffer);
|
struct music_chunk *chunk = music_buffer_allocate(player_buffer);
|
||||||
@ -519,18 +563,9 @@ static void player_process_command(struct player *player)
|
|||||||
yet - don't open the audio device yet */
|
yet - don't open the audio device yet */
|
||||||
player_lock(pc);
|
player_lock(pc);
|
||||||
|
|
||||||
pc->state = PLAYER_STATE_PLAY;
|
|
||||||
} else if (audio_output_all_open(&player->play_audio_format, player_buffer)) {
|
|
||||||
/* unpaused, continue playing */
|
|
||||||
player_lock(pc);
|
|
||||||
|
|
||||||
pc->state = PLAYER_STATE_PLAY;
|
pc->state = PLAYER_STATE_PLAY;
|
||||||
} else {
|
} else {
|
||||||
/* the audio device has failed - rollback to
|
player_open_output(player);
|
||||||
pause mode */
|
|
||||||
pc->error = PLAYER_ERROR_AUDIO;
|
|
||||||
|
|
||||||
player->paused = true;
|
|
||||||
|
|
||||||
player_lock(pc);
|
player_lock(pc);
|
||||||
}
|
}
|
||||||
@ -567,8 +602,7 @@ static void player_process_command(struct player *player)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_REFRESH:
|
case PLAYER_COMMAND_REFRESH:
|
||||||
if (audio_format_defined(&player->play_audio_format) &&
|
if (player->output_open && !player->paused) {
|
||||||
!player->paused) {
|
|
||||||
player_unlock(pc);
|
player_unlock(pc);
|
||||||
audio_output_all_check();
|
audio_output_all_check();
|
||||||
player_lock(pc);
|
player_lock(pc);
|
||||||
@ -823,6 +857,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
.decoder_starting = false,
|
.decoder_starting = false,
|
||||||
.paused = false,
|
.paused = false,
|
||||||
.queued = true,
|
.queued = true,
|
||||||
|
.output_open = false,
|
||||||
.song = NULL,
|
.song = NULL,
|
||||||
.xfade = XFADE_UNKNOWN,
|
.xfade = XFADE_UNKNOWN,
|
||||||
.cross_fading = false,
|
.cross_fading = false,
|
||||||
@ -847,6 +882,10 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
|
|
||||||
player_lock(pc);
|
player_lock(pc);
|
||||||
pc->state = PLAYER_STATE_PLAY;
|
pc->state = PLAYER_STATE_PLAY;
|
||||||
|
|
||||||
|
if (pc->command == PLAYER_COMMAND_SEEK)
|
||||||
|
player.elapsed_time = pc->seek_where;
|
||||||
|
|
||||||
player_command_finished_locked(pc);
|
player_command_finished_locked(pc);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -871,7 +910,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
/* not enough decoded buffer space yet */
|
/* not enough decoded buffer space yet */
|
||||||
|
|
||||||
if (!player.paused &&
|
if (!player.paused &&
|
||||||
audio_format_defined(&player.play_audio_format) &&
|
player.output_open &&
|
||||||
audio_output_all_check() < 4 &&
|
audio_output_all_check() < 4 &&
|
||||||
!player_send_silence(&player))
|
!player_send_silence(&player))
|
||||||
break;
|
break;
|
||||||
@ -976,7 +1015,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
audio_output_all_drain();
|
audio_output_all_drain();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (player.output_open) {
|
||||||
/* the decoder is too busy and hasn't provided
|
/* the decoder is too busy and hasn't provided
|
||||||
new PCM data in time: send silence (if the
|
new PCM data in time: send silence (if the
|
||||||
output pipe is empty) */
|
output pipe is empty) */
|
||||||
@ -1025,6 +1064,7 @@ player_task(gpointer arg)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
switch (pc->command) {
|
switch (pc->command) {
|
||||||
|
case PLAYER_COMMAND_SEEK:
|
||||||
case PLAYER_COMMAND_QUEUE:
|
case PLAYER_COMMAND_QUEUE:
|
||||||
assert(pc->next_song != NULL);
|
assert(pc->next_song != NULL);
|
||||||
|
|
||||||
@ -1038,7 +1078,6 @@ player_task(gpointer arg)
|
|||||||
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case PLAYER_COMMAND_SEEK:
|
|
||||||
case PLAYER_COMMAND_PAUSE:
|
case PLAYER_COMMAND_PAUSE:
|
||||||
pc->next_song = NULL;
|
pc->next_song = NULL;
|
||||||
player_command_finished_locked(pc);
|
player_command_finished_locked(pc);
|
||||||
|
@ -115,9 +115,7 @@ playlist_check_translate_song(struct song *song, const char *base_uri,
|
|||||||
|
|
||||||
if (g_path_is_absolute(uri)) {
|
if (g_path_is_absolute(uri)) {
|
||||||
/* XXX fs_charset vs utf8? */
|
/* XXX fs_charset vs utf8? */
|
||||||
char *prefix = base_uri != NULL
|
char *prefix = map_directory_fs(db_get_root());
|
||||||
? map_uri_fs(base_uri)
|
|
||||||
: map_directory_fs(db_get_root());
|
|
||||||
|
|
||||||
if (prefix != NULL && g_str_has_prefix(uri, prefix) &&
|
if (prefix != NULL && g_str_has_prefix(uri, prefix) &&
|
||||||
uri[strlen(prefix)] == '/')
|
uri[strlen(prefix)] == '/')
|
||||||
@ -130,6 +128,7 @@ playlist_check_translate_song(struct song *song, const char *base_uri,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base_uri = NULL;
|
||||||
g_free(prefix);
|
g_free(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user