Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
5c0576ca
Commit
5c0576ca
authored
Oct 06, 2011
by
Max Kellermann
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'v0.16.x'
Conflicts: configure.ac src/player_control.c src/player_thread.c src/playlist_song.c
parents
4e909f94
039b3544
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
173 additions
and
54 deletions
+173
-54
Makefile.am
Makefile.am
+9
-0
NEWS
NEWS
+7
-0
configure.ac
configure.ac
+8
-0
mpd.service.in
mpd.service.in
+9
-0
decoder_api.c
src/decoder_api.c
+46
-15
decoder_control.c
src/decoder_control.c
+3
-0
decoder_control.h
src/decoder_control.h
+20
-0
decoder_thread.c
src/decoder_thread.c
+1
-1
output_control.c
src/output_control.c
+0
-3
player_control.c
src/player_control.c
+0
-3
player_thread.c
src/player_thread.c
+68
-29
playlist_song.c
src/playlist_song.c
+2
-3
No files found.
Makefile.am
View file @
5c0576ca
...
...
@@ -873,6 +873,15 @@ FILTER_SRC = \
#
# systemd unit
#
if
HAVE_SYSTEMD
systemdsystemunit_DATA
=
\
mpd.service
endif
#
# Sparse code analysis
#
# sparse is a semantic parser
...
...
NEWS
View file @
5c0576ca
...
...
@@ -37,7 +37,14 @@ ver 0.16.5 (2010/??/??)
- ffmpeg: higher precision timestamps
- ffmpeg: don't require key frame for 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
* install systemd service file if systemd is available
ver 0.16.4 (2011/09/01)
...
...
configure.ac
View file @
5c0576ca
...
...
@@ -34,6 +34,13 @@ AM_CONDITIONAL(HAVE_CXX, test x$HAVE_CXX = xyes)
AC_PROG_INSTALL
AC_PROG_MAKE_SET
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 Declare Variables
...
...
@@ -1617,5 +1624,6 @@ dnl Generate files
dnl ---------------------------------------------------------------------------
AC_OUTPUT(Makefile)
AC_OUTPUT(doc/doxygen.conf)
AC_OUTPUT(mpd.service)
echo 'MPD is ready for compilation, type "make" to begin.'
mpd.service.in
0 → 100644
View file @
5c0576ca
[Unit]
Description=Music Player Daemon
After=sound.target
[Service]
ExecStart=@prefix@/bin/mpd --no-daemon
[Install]
WantedBy=multi-user.target
src/decoder_api.c
View file @
5c0576ca
...
...
@@ -77,30 +77,54 @@ decoder_initialized(struct decoder *decoder,
}
/**
* Returns the current decoder command. May return a "virtual"
* synthesized command, e.g. to seek to the beginning of the CUE
* track.
* Checks if we need an "initial seek". If so, then the initial seek
* is prepared, and the function returns true.
*/
G_GNUC_PURE
static
enum
decoder_command
decoder_
get_virtual_command
(
struct
decoder
*
decoder
)
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
)
return
DECODE_COMMAND_SEEK
;
/* 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
DECODE_COMMAND_SEEK
;
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"
* synthesized command, e.g. to seek to the beginning of the CUE
* track.
*/
G_GNUC_PURE
static
enum
decoder_command
decoder_get_virtual_command
(
struct
decoder
*
decoder
)
{
const
struct
decoder_control
*
dc
=
decoder
->
dc
;
assert
(
dc
->
pipe
!=
NULL
);
if
(
decoder_prepare_initial_seek
(
decoder
))
return
DECODE_COMMAND_SEEK
;
return
dc
->
command
;
}
...
...
@@ -130,7 +154,7 @@ decoder_command_finished(struct decoder *decoder)
assert
(
music_pipe_empty
(
dc
->
pipe
));
decoder
->
initial_seek_running
=
false
;
decoder
->
timestamp
=
dc
->
s
ong
->
s
tart_ms
/
1000
.;
decoder
->
timestamp
=
dc
->
start_ms
/
1000
.;
decoder_unlock
(
dc
);
return
;
}
...
...
@@ -162,7 +186,7 @@ double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
assert
(
dc
->
pipe
!=
NULL
);
if
(
decoder
->
initial_seek_running
)
return
dc
->
s
ong
->
s
tart_ms
/
1000
.;
return
dc
->
start_ms
/
1000
.;
assert
(
dc
->
command
==
DECODE_COMMAND_SEEK
);
...
...
@@ -177,10 +201,12 @@ void decoder_seek_error(struct decoder * decoder)
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,
what now? - no idea, ignoring the problem for now. */
decoder
->
initial_seek_running
=
false
;
return
;
}
assert
(
dc
->
command
==
DECODE_COMMAND_SEEK
);
...
...
@@ -424,8 +450,8 @@ decoder_data(struct decoder *decoder,
decoder
->
timestamp
+=
(
double
)
nbytes
/
audio_format_time_to_size
(
&
dc
->
out_audio_format
);
if
(
dc
->
song
->
end_ms
>
0
&&
decoder
->
timestamp
>=
dc
->
song
->
end_ms
/
1000
.
0
)
if
(
dc
->
end_ms
>
0
&&
decoder
->
timestamp
>=
dc
->
end_ms
/
1000
.
0
)
/* the end of this range has been reached:
stop decoding */
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
);
/* 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 */
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 */
cmd
=
do_send_tag
(
decoder
,
tag
);
if
(
cmd
==
DECODE_COMMAND_NONE
)
cmd
=
decoder_get_virtual_command
(
decoder
);
return
cmd
;
}
...
...
src/decoder_control.c
View file @
5c0576ca
...
...
@@ -96,6 +96,7 @@ dc_command_async(struct decoder_control *dc, enum decoder_command cmd)
void
dc_start
(
struct
decoder_control
*
dc
,
struct
song
*
song
,
unsigned
start_ms
,
unsigned
end_ms
,
struct
music_buffer
*
buffer
,
struct
music_pipe
*
pipe
)
{
assert
(
song
!=
NULL
);
...
...
@@ -104,6 +105,8 @@ dc_start(struct decoder_control *dc, struct song *song,
assert
(
music_pipe_empty
(
pipe
));
dc
->
song
=
song
;
dc
->
start_ms
=
start_ms
;
dc
->
end_ms
=
end_ms
;
dc
->
buffer
=
buffer
;
dc
->
pipe
=
pipe
;
dc_command
(
dc
,
DECODE_COMMAND_START
);
...
...
src/decoder_control.h
View file @
5c0576ca
...
...
@@ -85,6 +85,23 @@ struct decoder_control {
*/
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
;
/** the #music_chunk allocator */
...
...
@@ -229,11 +246,14 @@ decoder_current_song(const struct decoder_control *dc)
*
* @param the decoder
* @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
* the caller)
*/
void
dc_start
(
struct
decoder_control
*
dc
,
struct
song
*
song
,
unsigned
start_ms
,
unsigned
end_ms
,
struct
music_buffer
*
buffer
,
struct
music_pipe
*
pipe
);
void
...
...
src/decoder_thread.c
View file @
5c0576ca
...
...
@@ -380,7 +380,7 @@ decoder_run_song(struct decoder_control *dc,
{
struct
decoder
decoder
=
{
.
dc
=
dc
,
.
initial_seek_pending
=
song
->
start_ms
>
0
,
.
initial_seek_pending
=
dc
->
start_ms
>
0
,
.
initial_seek_running
=
false
,
};
int
ret
;
...
...
src/output_control.c
View file @
5c0576ca
...
...
@@ -126,9 +126,6 @@ audio_output_disable(struct audio_output *ao)
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.
*/
...
...
src/player_control.c
View file @
5c0576ca
...
...
@@ -319,9 +319,6 @@ pc_seek(struct player_control *pc, struct song *song, float seek_time)
{
assert
(
song
!=
NULL
);
if
(
pc
->
state
==
PLAYER_STATE_STOP
)
return
false
;
player_lock
(
pc
);
pc
->
next_song
=
song
;
pc
->
seek_where
=
seek_time
;
...
...
src/player_thread.c
View file @
5c0576ca
...
...
@@ -76,6 +76,14 @@ struct player {
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
*/
struct
song
*
song
;
...
...
@@ -150,7 +158,13 @@ player_dc_start(struct player *player, struct music_pipe *pipe)
assert
(
player
->
queued
||
pc
->
command
==
PLAYER_COMMAND_SEEK
);
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
);
}
/**
...
...
@@ -277,6 +291,46 @@ real_song_duration(const struct song *song, double decoder_duration)
}
/**
* 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
* player_wait_for_decoder()). This function checks if the decoder
* initialization has completed yet.
...
...
@@ -308,7 +362,7 @@ player_check_decoder_startup(struct player *player)
decoder_unlock
(
dc
);
if
(
audio_format_defined
(
&
player
->
play_audio_format
)
&&
if
(
player
->
output_open
&&
!
audio_output_all_wait
(
pc
,
1
))
/* the output devices havn't finished playing
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
->
decoder_starting
=
false
;
if
(
!
player
->
paused
&&
!
audio_output_all_open
(
&
dc
->
out_audio_format
,
player_buffer
))
{
if
(
!
player
->
paused
&&
!
player_open_output
(
player
))
{
char
*
uri
=
song_get_uri
(
dc
->
song
);
g_warning
(
"problems opening audio device "
"while playing
\"
%s
\"
"
,
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
;
}
...
...
@@ -363,6 +406,7 @@ player_check_decoder_startup(struct player *player)
static
bool
player_send_silence
(
struct
player
*
player
)
{
assert
(
player
->
output_open
);
assert
(
audio_format_defined
(
&
player
->
play_audio_format
));
struct
music_chunk
*
chunk
=
music_buffer_allocate
(
player_buffer
);
...
...
@@ -520,17 +564,8 @@ static void player_process_command(struct player *player)
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
;
}
else
{
/* the audio device has failed - rollback to
pause mode */
pc
->
error
=
PLAYER_ERROR_AUDIO
;
player
->
paused
=
true
;
player_open_output
(
player
);
player_lock
(
pc
);
}
...
...
@@ -567,8 +602,7 @@ static void player_process_command(struct player *player)
break
;
case
PLAYER_COMMAND_REFRESH
:
if
(
audio_format_defined
(
&
player
->
play_audio_format
)
&&
!
player
->
paused
)
{
if
(
player
->
output_open
&&
!
player
->
paused
)
{
player_unlock
(
pc
);
audio_output_all_check
();
player_lock
(
pc
);
...
...
@@ -823,6 +857,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
.
decoder_starting
=
false
,
.
paused
=
false
,
.
queued
=
true
,
.
output_open
=
false
,
.
song
=
NULL
,
.
xfade
=
XFADE_UNKNOWN
,
.
cross_fading
=
false
,
...
...
@@ -847,6 +882,10 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
player_lock
(
pc
);
pc
->
state
=
PLAYER_STATE_PLAY
;
if
(
pc
->
command
==
PLAYER_COMMAND_SEEK
)
player
.
elapsed_time
=
pc
->
seek_where
;
player_command_finished_locked
(
pc
);
while
(
true
)
{
...
...
@@ -871,7 +910,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
/* not enough decoded buffer space yet */
if
(
!
player
.
paused
&&
audio_format_defined
(
&
player
.
play_audio_format
)
&&
player
.
output_open
&&
audio_output_all_check
()
<
4
&&
!
player_send_silence
(
&
player
))
break
;
...
...
@@ -976,7 +1015,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
audio_output_all_drain
();
break
;
}
}
else
{
}
else
if
(
player
.
output_open
)
{
/* the decoder is too busy and hasn't provided
new PCM data in time: send silence (if the
output pipe is empty) */
...
...
@@ -1025,6 +1064,7 @@ player_task(gpointer arg)
while
(
1
)
{
switch
(
pc
->
command
)
{
case
PLAYER_COMMAND_SEEK
:
case
PLAYER_COMMAND_QUEUE
:
assert
(
pc
->
next_song
!=
NULL
);
...
...
@@ -1038,7 +1078,6 @@ player_task(gpointer arg)
/* fall through */
case
PLAYER_COMMAND_SEEK
:
case
PLAYER_COMMAND_PAUSE
:
pc
->
next_song
=
NULL
;
player_command_finished_locked
(
pc
);
...
...
src/playlist_song.c
View file @
5c0576ca
...
...
@@ -115,9 +115,7 @@ playlist_check_translate_song(struct song *song, const char *base_uri,
if
(
g_path_is_absolute
(
uri
))
{
/* XXX fs_charset vs utf8? */
char
*
prefix
=
base_uri
!=
NULL
?
map_uri_fs
(
base_uri
)
:
map_directory_fs
(
db_get_root
());
char
*
prefix
=
map_directory_fs
(
db_get_root
());
if
(
prefix
!=
NULL
&&
g_str_has_prefix
(
uri
,
prefix
)
&&
uri
[
strlen
(
prefix
)]
==
'/'
)
...
...
@@ -130,6 +128,7 @@ playlist_check_translate_song(struct song *song, const char *base_uri,
return
NULL
;
}
base_uri
=
NULL
;
g_free
(
prefix
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment