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
6ef428af
Commit
6ef428af
authored
Oct 31, 2009
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
decoder_control: removed the global variable "dc"
Allocate a decoder_control object where needed, and pass it around. This will allow more than one decoder thread one day.
parent
806496df
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
375 additions
and
315 deletions
+375
-315
decoder_api.c
src/decoder_api.c
+78
-60
decoder_control.c
src/decoder_control.c
+62
-59
decoder_control.h
src/decoder_control.h
+50
-44
decoder_internal.c
src/decoder_internal.c
+19
-16
decoder_internal.h
src/decoder_internal.h
+2
-0
decoder_thread.c
src/decoder_thread.c
+67
-58
decoder_thread.h
src/decoder_thread.h
+4
-1
main.c
src/main.c
+0
-3
player_control.c
src/player_control.c
+2
-2
player_control.h
src/player_control.h
+3
-1
player_thread.c
src/player_thread.c
+88
-71
No files found.
src/decoder_api.c
View file @
6ef428af
...
...
@@ -37,12 +37,15 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "decoder"
void
decoder_initialized
(
G_GNUC_UNUSED
struct
decoder
*
decoder
,
void
decoder_initialized
(
struct
decoder
*
decoder
,
const
struct
audio_format
*
audio_format
,
bool
seekable
,
float
total_time
)
{
assert
(
dc
.
state
==
DECODE_STATE_START
);
assert
(
dc
.
pipe
!=
NULL
);
struct
decoder_control
*
dc
=
decoder
->
dc
;
assert
(
dc
->
state
==
DECODE_STATE_START
);
assert
(
dc
->
pipe
!=
NULL
);
assert
(
decoder
!=
NULL
);
assert
(
decoder
->
stream_tag
==
NULL
);
assert
(
decoder
->
decoder_tag
==
NULL
);
...
...
@@ -51,86 +54,98 @@ void decoder_initialized(G_GNUC_UNUSED struct decoder * decoder,
assert
(
audio_format_defined
(
audio_format
));
assert
(
audio_format_valid
(
audio_format
));
dc
.
in_audio_format
=
*
audio_format
;
getOutputAudioFormat
(
audio_format
,
&
dc
.
out_audio_format
);
dc
->
in_audio_format
=
*
audio_format
;
getOutputAudioFormat
(
audio_format
,
&
dc
->
out_audio_format
);
dc
.
seekable
=
seekable
;
dc
.
total_time
=
total_time
;
dc
->
seekable
=
seekable
;
dc
->
total_time
=
total_time
;
decoder_lock
();
dc
.
state
=
DECODE_STATE_DECODE
;
decoder_unlock
();
decoder_lock
(
dc
);
dc
->
state
=
DECODE_STATE_DECODE
;
decoder_unlock
(
dc
);
player_lock_signal
();
g_debug
(
"audio_format=%u:%u:%u, seekable=%s"
,
dc
.
in_audio_format
.
sample_rate
,
dc
.
in_audio_format
.
bits
,
dc
.
in_audio_format
.
channels
,
dc
->
in_audio_format
.
sample_rate
,
dc
->
in_audio_format
.
bits
,
dc
->
in_audio_format
.
channels
,
seekable
?
"true"
:
"false"
);
if
(
!
audio_format_equals
(
&
dc
.
in_audio_format
,
&
dc
.
out_audio_format
))
if
(
!
audio_format_equals
(
&
dc
->
in_audio_format
,
&
dc
->
out_audio_format
))
g_debug
(
"converting to %u:%u:%u"
,
dc
.
out_audio_format
.
sample_rate
,
dc
.
out_audio_format
.
bits
,
dc
.
out_audio_format
.
channels
);
dc
->
out_audio_format
.
sample_rate
,
dc
->
out_audio_format
.
bits
,
dc
->
out_audio_format
.
channels
);
}
char
*
decoder_get_uri
(
G_GNUC_UNUSED
struct
decoder
*
decoder
)
{
assert
(
dc
.
pipe
!=
NULL
);
const
struct
decoder_control
*
dc
=
decoder
->
dc
;
assert
(
dc
->
pipe
!=
NULL
);
return
song_get_uri
(
dc
.
current_song
);
return
song_get_uri
(
dc
->
current_song
);
}
enum
decoder_command
decoder_get_command
(
G_GNUC_UNUSED
struct
decoder
*
decoder
)
{
assert
(
dc
.
pipe
!=
NULL
);
const
struct
decoder_control
*
dc
=
decoder
->
dc
;
assert
(
dc
->
pipe
!=
NULL
);
return
dc
.
command
;
return
dc
->
command
;
}
void
decoder_command_finished
(
G_GNUC_UNUSED
struct
decoder
*
decoder
)
{
decoder_lock
()
;
struct
decoder_control
*
dc
=
decoder
->
dc
;
assert
(
dc
.
command
!=
DECODE_COMMAND_NONE
);
assert
(
dc
.
command
!=
DECODE_COMMAND_SEEK
||
dc
.
seek_error
||
decoder
->
seeking
);
assert
(
dc
.
pipe
!=
NULL
);
decoder_lock
(
dc
);
if
(
dc
.
command
==
DECODE_COMMAND_SEEK
)
{
assert
(
dc
->
command
!=
DECODE_COMMAND_NONE
);
assert
(
dc
->
command
!=
DECODE_COMMAND_SEEK
||
dc
->
seek_error
||
decoder
->
seeking
);
assert
(
dc
->
pipe
!=
NULL
);
if
(
dc
->
command
==
DECODE_COMMAND_SEEK
)
{
/* delete frames from the old song position */
if
(
decoder
->
chunk
!=
NULL
)
{
music_buffer_return
(
dc
.
buffer
,
decoder
->
chunk
);
music_buffer_return
(
dc
->
buffer
,
decoder
->
chunk
);
decoder
->
chunk
=
NULL
;
}
music_pipe_clear
(
dc
.
pipe
,
dc
.
buffer
);
music_pipe_clear
(
dc
->
pipe
,
dc
->
buffer
);
}
dc
.
command
=
DECODE_COMMAND_NONE
;
decoder_unlock
();
dc
->
command
=
DECODE_COMMAND_NONE
;
decoder_unlock
(
dc
);
player_lock_signal
();
}
double
decoder_seek_where
(
G_GNUC_UNUSED
struct
decoder
*
decoder
)
{
assert
(
dc
.
command
==
DECODE_COMMAND_SEEK
);
assert
(
dc
.
pipe
!=
NULL
);
const
struct
decoder_control
*
dc
=
decoder
->
dc
;
assert
(
dc
->
command
==
DECODE_COMMAND_SEEK
);
assert
(
dc
->
pipe
!=
NULL
);
decoder
->
seeking
=
true
;
return
dc
.
seek_where
;
return
dc
->
seek_where
;
}
void
decoder_seek_error
(
struct
decoder
*
decoder
)
{
assert
(
dc
.
command
==
DECODE_COMMAND_SEEK
);
assert
(
dc
.
pipe
!=
NULL
);
struct
decoder_control
*
dc
=
decoder
->
dc
;
assert
(
dc
->
command
==
DECODE_COMMAND_SEEK
);
assert
(
dc
->
pipe
!=
NULL
);
dc
.
seek_error
=
true
;
dc
->
seek_error
=
true
;
decoder_command_finished
(
decoder
);
}
...
...
@@ -138,11 +153,12 @@ size_t decoder_read(struct decoder *decoder,
struct
input_stream
*
is
,
void
*
buffer
,
size_t
length
)
{
const
struct
decoder_control
*
dc
=
decoder
->
dc
;
size_t
nbytes
;
assert
(
decoder
==
NULL
||
dc
.
state
==
DECODE_STATE_START
||
dc
.
state
==
DECODE_STATE_DECODE
);
dc
->
state
==
DECODE_STATE_START
||
dc
->
state
==
DECODE_STATE_DECODE
);
assert
(
is
!=
NULL
);
assert
(
buffer
!=
NULL
);
...
...
@@ -155,9 +171,9 @@ size_t decoder_read(struct decoder *decoder,
/* ignore the SEEK command during initialization,
the plugin should handle that after it has
initialized successfully */
(
dc
.
command
!=
DECODE_COMMAND_SEEK
||
(
dc
.
state
!=
DECODE_STATE_START
&&
!
decoder
->
seeking
))
&&
dc
.
command
!=
DECODE_COMMAND_NONE
)
(
dc
->
command
!=
DECODE_COMMAND_SEEK
||
(
dc
->
state
!=
DECODE_STATE_START
&&
!
decoder
->
seeking
))
&&
dc
->
command
!=
DECODE_COMMAND_NONE
)
return
0
;
nbytes
=
input_stream_read
(
is
,
buffer
,
length
);
...
...
@@ -191,8 +207,8 @@ do_send_tag(struct decoder *decoder, struct input_stream *is,
chunk
=
decoder_get_chunk
(
decoder
,
is
);
if
(
chunk
==
NULL
)
{
assert
(
d
c
.
command
!=
DECODE_COMMAND_NONE
);
return
d
c
.
command
;
assert
(
d
ecoder
->
dc
->
command
!=
DECODE_COMMAND_NONE
);
return
d
ecoder
->
dc
->
command
;
}
chunk
->
tag
=
tag_dup
(
tag
);
...
...
@@ -231,17 +247,18 @@ decoder_data(struct decoder *decoder,
float
data_time
,
uint16_t
bitRate
,
struct
replay_gain_info
*
replay_gain_info
)
{
struct
decoder_control
*
dc
=
decoder
->
dc
;
const
char
*
data
=
_data
;
GError
*
error
=
NULL
;
enum
decoder_command
cmd
;
assert
(
dc
.
state
==
DECODE_STATE_DECODE
);
assert
(
dc
.
pipe
!=
NULL
);
assert
(
length
%
audio_format_frame_size
(
&
dc
.
in_audio_format
)
==
0
);
assert
(
dc
->
state
==
DECODE_STATE_DECODE
);
assert
(
dc
->
pipe
!=
NULL
);
assert
(
length
%
audio_format_frame_size
(
&
dc
->
in_audio_format
)
==
0
);
decoder_lock
();
cmd
=
dc
.
command
;
decoder_unlock
();
decoder_lock
(
dc
);
cmd
=
dc
->
command
;
decoder_unlock
(
dc
);
if
(
cmd
==
DECODE_COMMAND_STOP
||
cmd
==
DECODE_COMMAND_SEEK
||
length
==
0
)
...
...
@@ -266,10 +283,10 @@ decoder_data(struct decoder *decoder,
return
cmd
;
}
if
(
!
audio_format_equals
(
&
dc
.
in_audio_format
,
&
dc
.
out_audio_format
))
{
if
(
!
audio_format_equals
(
&
dc
->
in_audio_format
,
&
dc
->
out_audio_format
))
{
data
=
pcm_convert
(
&
decoder
->
conv_state
,
&
dc
.
in_audio_format
,
data
,
length
,
&
dc
.
out_audio_format
,
&
length
,
&
dc
->
in_audio_format
,
data
,
length
,
&
dc
->
out_audio_format
,
&
length
,
&
error
);
if
(
data
==
NULL
)
{
/* the PCM conversion has failed - stop
...
...
@@ -288,11 +305,11 @@ decoder_data(struct decoder *decoder,
chunk
=
decoder_get_chunk
(
decoder
,
is
);
if
(
chunk
==
NULL
)
{
assert
(
dc
.
command
!=
DECODE_COMMAND_NONE
);
return
dc
.
command
;
assert
(
dc
->
command
!=
DECODE_COMMAND_NONE
);
return
dc
->
command
;
}
dest
=
music_chunk_write
(
chunk
,
&
dc
.
out_audio_format
,
dest
=
music_chunk_write
(
chunk
,
&
dc
->
out_audio_format
,
data_time
,
bitRate
,
&
nbytes
);
if
(
dest
==
NULL
)
{
/* the chunk is full, flush it */
...
...
@@ -314,13 +331,13 @@ decoder_data(struct decoder *decoder,
if
(
replay_gain_mode
!=
REPLAY_GAIN_OFF
)
replay_gain_apply
(
replay_gain_info
,
dest
,
nbytes
,
&
dc
.
out_audio_format
);
&
dc
->
out_audio_format
);
else
if
(
normalizationEnabled
)
normalizeData
(
dest
,
nbytes
,
&
dc
.
out_audio_format
);
normalizeData
(
dest
,
nbytes
,
&
dc
->
out_audio_format
);
/* expand the music pipe chunk */
full
=
music_chunk_expand
(
chunk
,
&
dc
.
out_audio_format
,
nbytes
);
full
=
music_chunk_expand
(
chunk
,
&
dc
->
out_audio_format
,
nbytes
);
if
(
full
)
{
/* the chunk is full, flush it */
decoder_flush_chunk
(
decoder
);
...
...
@@ -338,10 +355,11 @@ enum decoder_command
decoder_tag
(
G_GNUC_UNUSED
struct
decoder
*
decoder
,
struct
input_stream
*
is
,
const
struct
tag
*
tag
)
{
const
struct
decoder_control
*
dc
=
decoder
->
dc
;
enum
decoder_command
cmd
;
assert
(
dc
.
state
==
DECODE_STATE_DECODE
);
assert
(
dc
.
pipe
!=
NULL
);
assert
(
dc
->
state
==
DECODE_STATE_DECODE
);
assert
(
dc
->
pipe
!=
NULL
);
assert
(
tag
!=
NULL
);
/* save the tag */
...
...
src/decoder_control.c
View file @
6ef428af
...
...
@@ -22,131 +22,134 @@
#include <assert.h>
struct
decoder_control
dc
;
void
dc_init
(
void
)
void
dc_init
(
struct
decoder_control
*
dc
)
{
dc
.
mutex
=
g_mutex_new
();
dc
.
cond
=
g_cond_new
();
dc
->
thread
=
NULL
;
dc
->
mutex
=
g_mutex_new
();
dc
->
cond
=
g_cond_new
();
dc
.
state
=
DECODE_STATE_STOP
;
dc
.
command
=
DECODE_COMMAND_NONE
;
dc
->
state
=
DECODE_STATE_STOP
;
dc
->
command
=
DECODE_COMMAND_NONE
;
}
void
dc_deinit
(
void
)
void
dc_deinit
(
struct
decoder_control
*
dc
)
{
g_cond_free
(
dc
.
cond
);
g_mutex_free
(
dc
.
mutex
);
g_cond_free
(
dc
->
cond
);
g_mutex_free
(
dc
->
mutex
);
}
static
void
dc_command_wait_locked
(
void
)
dc_command_wait_locked
(
struct
decoder_control
*
dc
)
{
while
(
dc
.
command
!=
DECODE_COMMAND_NONE
)
{
decoder_signal
();
player_wait_decoder
();
while
(
dc
->
command
!=
DECODE_COMMAND_NONE
)
{
decoder_signal
(
dc
);
player_wait_decoder
(
dc
);
}
}
void
dc_command_wait
(
void
)
dc_command_wait
(
struct
decoder_control
*
dc
)
{
decoder_lock
();
dc_command_wait_locked
();
decoder_unlock
();
decoder_lock
(
dc
);
dc_command_wait_locked
(
dc
);
decoder_unlock
(
dc
);
}
static
void
dc_command_locked
(
enum
decoder_command
cmd
)
dc_command_locked
(
struct
decoder_control
*
dc
,
enum
decoder_command
cmd
)
{
dc
.
command
=
cmd
;
dc_command_wait_locked
();
dc
->
command
=
cmd
;
dc_command_wait_locked
(
dc
);
}
static
void
dc_command
(
enum
decoder_command
cmd
)
dc_command
(
struct
decoder_control
*
dc
,
enum
decoder_command
cmd
)
{
decoder_lock
();
dc_command_locked
(
cmd
);
decoder_unlock
();
decoder_lock
(
dc
);
dc_command_locked
(
dc
,
cmd
);
decoder_unlock
(
dc
);
}
static
void
dc_command_async
(
enum
decoder_command
cmd
)
static
void
dc_command_async
(
struct
decoder_control
*
dc
,
enum
decoder_command
cmd
)
{
decoder_lock
();
decoder_lock
(
dc
);
dc
.
command
=
cmd
;
decoder_signal
();
dc
->
command
=
cmd
;
decoder_signal
(
dc
);
decoder_unlock
();
decoder_unlock
(
dc
);
}
void
dc_start
(
struct
song
*
song
)
dc_start
(
struct
decoder_control
*
dc
,
struct
song
*
song
)
{
assert
(
dc
.
pipe
!=
NULL
);
assert
(
dc
->
pipe
!=
NULL
);
assert
(
song
!=
NULL
);
dc
.
next_song
=
song
;
dc_command
(
DECODE_COMMAND_START
);
dc
->
next_song
=
song
;
dc_command
(
dc
,
DECODE_COMMAND_START
);
}
void
dc_start_async
(
struct
song
*
song
)
dc_start_async
(
struct
decoder_control
*
dc
,
struct
song
*
song
)
{
assert
(
dc
.
pipe
!=
NULL
);
assert
(
dc
->
pipe
!=
NULL
);
assert
(
song
!=
NULL
);
dc
.
next_song
=
song
;
dc_command_async
(
DECODE_COMMAND_START
);
dc
->
next_song
=
song
;
dc_command_async
(
dc
,
DECODE_COMMAND_START
);
}
void
dc_stop
(
void
)
dc_stop
(
struct
decoder_control
*
dc
)
{
decoder_lock
();
decoder_lock
(
dc
);
if
(
dc
.
command
!=
DECODE_COMMAND_NONE
)
if
(
dc
->
command
!=
DECODE_COMMAND_NONE
)
/* Attempt to cancel the current command. If it's too
late and the decoder thread is already executing
the old command, we'll call STOP again in this
function (see below). */
dc_command_locked
(
DECODE_COMMAND_STOP
);
dc_command_locked
(
dc
,
DECODE_COMMAND_STOP
);
if
(
dc
.
state
!=
DECODE_STATE_STOP
&&
dc
.
state
!=
DECODE_STATE_ERROR
)
dc_command_locked
(
DECODE_COMMAND_STOP
);
if
(
dc
->
state
!=
DECODE_STATE_STOP
&&
dc
->
state
!=
DECODE_STATE_ERROR
)
dc_command_locked
(
dc
,
DECODE_COMMAND_STOP
);
decoder_unlock
();
decoder_unlock
(
dc
);
}
bool
dc_seek
(
double
where
)
dc_seek
(
struct
decoder_control
*
dc
,
double
where
)
{
assert
(
dc
.
state
!=
DECODE_STATE_START
);
assert
(
dc
->
state
!=
DECODE_STATE_START
);
assert
(
where
>=
0
.
0
);
if
(
dc
.
state
==
DECODE_STATE_STOP
||
dc
.
state
==
DECODE_STATE_ERROR
||
!
dc
.
seekable
)
if
(
dc
->
state
==
DECODE_STATE_STOP
||
dc
->
state
==
DECODE_STATE_ERROR
||
!
dc
->
seekable
)
return
false
;
dc
.
seek_where
=
where
;
dc
.
seek_error
=
false
;
dc_command
(
DECODE_COMMAND_SEEK
);
dc
->
seek_where
=
where
;
dc
->
seek_error
=
false
;
dc_command
(
dc
,
DECODE_COMMAND_SEEK
);
if
(
dc
.
seek_error
)
if
(
dc
->
seek_error
)
return
false
;
return
true
;
}
void
dc_quit
(
void
)
dc_quit
(
struct
decoder_control
*
dc
)
{
assert
(
dc
.
thread
!=
NULL
);
assert
(
dc
->
thread
!=
NULL
);
dc
.
quit
=
true
;
dc_command_async
(
DECODE_COMMAND_STOP
);
dc
->
quit
=
true
;
dc_command_async
(
dc
,
DECODE_COMMAND_STOP
);
g_thread_join
(
dc
.
thread
);
dc
.
thread
=
NULL
;
g_thread_join
(
dc
->
thread
);
dc
->
thread
=
NULL
;
}
src/decoder_control.h
View file @
6ef428af
...
...
@@ -83,28 +83,28 @@ struct decoder_control {
struct
music_pipe
*
pipe
;
};
extern
struct
decoder_control
dc
;
void
dc_init
(
void
);
void
dc_init
(
struct
decoder_control
*
dc
);
void
dc_deinit
(
void
);
void
dc_deinit
(
struct
decoder_control
*
dc
);
/**
* Locks the #decoder_control object.
*/
static
inline
void
decoder_lock
(
void
)
decoder_lock
(
struct
decoder_control
*
dc
)
{
g_mutex_lock
(
dc
.
mutex
);
g_mutex_lock
(
dc
->
mutex
);
}
/**
* Unlocks the #decoder_control object.
*/
static
inline
void
decoder_unlock
(
void
)
decoder_unlock
(
struct
decoder_control
*
dc
)
{
g_mutex_unlock
(
dc
.
mutex
);
g_mutex_unlock
(
dc
->
mutex
);
}
/**
...
...
@@ -113,9 +113,9 @@ decoder_unlock(void)
* prior to calling this function.
*/
static
inline
void
decoder_wait
(
void
)
decoder_wait
(
struct
decoder_control
*
dc
)
{
g_cond_wait
(
dc
.
cond
,
dc
.
mutex
);
g_cond_wait
(
dc
->
cond
,
dc
->
mutex
);
}
/**
...
...
@@ -124,75 +124,81 @@ decoder_wait(void)
* this function.
*/
static
inline
void
decoder_signal
(
void
)
decoder_signal
(
struct
decoder_control
*
dc
)
{
g_cond_signal
(
dc
.
cond
);
g_cond_signal
(
dc
->
cond
);
}
static
inline
bool
decoder_is_idle
(
void
)
static
inline
bool
decoder_is_idle
(
const
struct
decoder_control
*
dc
)
{
return
(
dc
.
state
==
DECODE_STATE_STOP
||
dc
.
state
==
DECODE_STATE_ERROR
)
&&
dc
.
command
!=
DECODE_COMMAND_START
;
return
(
dc
->
state
==
DECODE_STATE_STOP
||
dc
->
state
==
DECODE_STATE_ERROR
)
&&
dc
->
command
!=
DECODE_COMMAND_START
;
}
static
inline
bool
decoder_is_starting
(
void
)
static
inline
bool
decoder_is_starting
(
const
struct
decoder_control
*
dc
)
{
return
dc
.
command
==
DECODE_COMMAND_START
||
dc
.
state
==
DECODE_STATE_START
;
return
dc
->
command
==
DECODE_COMMAND_START
||
dc
->
state
==
DECODE_STATE_START
;
}
static
inline
bool
decoder_has_failed
(
void
)
static
inline
bool
decoder_has_failed
(
const
struct
decoder_control
*
dc
)
{
assert
(
dc
.
command
==
DECODE_COMMAND_NONE
);
assert
(
dc
->
command
==
DECODE_COMMAND_NONE
);
return
dc
.
state
==
DECODE_STATE_ERROR
;
return
dc
->
state
==
DECODE_STATE_ERROR
;
}
static
inline
bool
decoder_lock_is_idle
(
void
)
static
inline
bool
decoder_lock_is_idle
(
struct
decoder_control
*
dc
)
{
bool
ret
;
decoder_lock
();
ret
=
decoder_is_idle
();
decoder_unlock
();
decoder_lock
(
dc
);
ret
=
decoder_is_idle
(
dc
);
decoder_unlock
(
dc
);
return
ret
;
}
static
inline
bool
decoder_lock_is_starting
(
void
)
static
inline
bool
decoder_lock_is_starting
(
struct
decoder_control
*
dc
)
{
bool
ret
;
decoder_lock
();
ret
=
decoder_is_starting
();
decoder_unlock
();
decoder_lock
(
dc
);
ret
=
decoder_is_starting
(
dc
);
decoder_unlock
(
dc
);
return
ret
;
}
static
inline
bool
decoder_lock_has_failed
(
void
)
static
inline
bool
decoder_lock_has_failed
(
struct
decoder_control
*
dc
)
{
bool
ret
;
decoder_lock
();
ret
=
decoder_has_failed
();
decoder_unlock
();
decoder_lock
(
dc
);
ret
=
decoder_has_failed
(
dc
);
decoder_unlock
(
dc
);
return
ret
;
}
static
inline
struct
song
*
decoder_current_song
(
void
)
static
inline
const
struct
song
*
decoder_current_song
(
const
struct
decoder_control
*
dc
)
{
switch
(
dc
.
state
)
{
switch
(
dc
->
state
)
{
case
DECODE_STATE_STOP
:
case
DECODE_STATE_ERROR
:
return
NULL
;
case
DECODE_STATE_START
:
case
DECODE_STATE_DECODE
:
return
dc
.
current_song
;
return
dc
->
current_song
;
}
assert
(
false
);
...
...
@@ -200,21 +206,21 @@ decoder_current_song(void)
}
void
dc_command_wait
(
void
);
dc_command_wait
(
struct
decoder_control
*
dc
);
void
dc_start
(
struct
song
*
song
);
dc_start
(
struct
decoder_control
*
dc
,
struct
song
*
song
);
void
dc_start_async
(
struct
song
*
song
);
dc_start_async
(
struct
decoder_control
*
dc
,
struct
song
*
song
);
void
dc_stop
(
void
);
dc_stop
(
struct
decoder_control
*
dc
);
bool
dc_seek
(
double
where
);
dc_seek
(
struct
decoder_control
*
dc
,
double
where
);
void
dc_quit
(
void
);
dc_quit
(
struct
decoder_control
*
dc
);
#endif
src/decoder_internal.c
View file @
6ef428af
...
...
@@ -34,13 +34,13 @@
* potentially blocking operation.
*/
static
int
decoder_input_buffer
(
struct
input_stream
*
is
)
decoder_input_buffer
(
struct
decoder_control
*
dc
,
struct
input_stream
*
is
)
{
int
ret
;
decoder_unlock
();
decoder_unlock
(
dc
);
ret
=
input_stream_buffer
(
is
)
>
0
;
decoder_lock
();
decoder_lock
(
dc
);
return
ret
;
}
...
...
@@ -50,17 +50,17 @@ decoder_input_buffer(struct input_stream *is)
* one.
*/
static
enum
decoder_command
need_chunks
(
struct
input_stream
*
is
,
bool
do_wait
)
need_chunks
(
struct
decoder_control
*
dc
,
struct
input_stream
*
is
,
bool
do_wait
)
{
if
(
dc
.
command
==
DECODE_COMMAND_STOP
||
dc
.
command
==
DECODE_COMMAND_SEEK
)
return
dc
.
command
;
if
(
dc
->
command
==
DECODE_COMMAND_STOP
||
dc
->
command
==
DECODE_COMMAND_SEEK
)
return
dc
->
command
;
if
((
is
==
NULL
||
decoder_input_buffer
(
is
)
<=
0
)
&&
do_wait
)
{
decoder_wait
();
if
((
is
==
NULL
||
decoder_input_buffer
(
dc
,
is
)
<=
0
)
&&
do_wait
)
{
decoder_wait
(
dc
);
player_signal
();
return
dc
.
command
;
return
dc
->
command
;
}
return
DECODE_COMMAND_NONE
;
...
...
@@ -69,6 +69,7 @@ need_chunks(struct input_stream *is, bool do_wait)
struct
music_chunk
*
decoder_get_chunk
(
struct
decoder
*
decoder
,
struct
input_stream
*
is
)
{
struct
decoder_control
*
dc
=
decoder
->
dc
;
enum
decoder_command
cmd
;
assert
(
decoder
!=
NULL
);
...
...
@@ -77,13 +78,13 @@ decoder_get_chunk(struct decoder *decoder, struct input_stream *is)
return
decoder
->
chunk
;
do
{
decoder
->
chunk
=
music_buffer_allocate
(
dc
.
buffer
);
decoder
->
chunk
=
music_buffer_allocate
(
dc
->
buffer
);
if
(
decoder
->
chunk
!=
NULL
)
return
decoder
->
chunk
;
decoder_lock
();
cmd
=
need_chunks
(
is
,
true
);
decoder_unlock
();
decoder_lock
(
dc
);
cmd
=
need_chunks
(
dc
,
is
,
true
);
decoder_unlock
(
dc
);
}
while
(
cmd
==
DECODE_COMMAND_NONE
);
return
NULL
;
...
...
@@ -92,13 +93,15 @@ decoder_get_chunk(struct decoder *decoder, struct input_stream *is)
void
decoder_flush_chunk
(
struct
decoder
*
decoder
)
{
struct
decoder_control
*
dc
=
decoder
->
dc
;
assert
(
decoder
!=
NULL
);
assert
(
decoder
->
chunk
!=
NULL
);
if
(
music_chunk_is_empty
(
decoder
->
chunk
))
music_buffer_return
(
dc
.
buffer
,
decoder
->
chunk
);
music_buffer_return
(
dc
->
buffer
,
decoder
->
chunk
);
else
music_pipe_push
(
dc
.
pipe
,
decoder
->
chunk
);
music_pipe_push
(
dc
->
pipe
,
decoder
->
chunk
);
decoder
->
chunk
=
NULL
;
}
src/decoder_internal.h
View file @
6ef428af
...
...
@@ -26,6 +26,8 @@
struct
input_stream
;
struct
decoder
{
struct
decoder_control
*
dc
;
struct
pcm_convert_state
conv_state
;
bool
seeking
;
...
...
src/decoder_thread.c
View file @
6ef428af
...
...
@@ -47,21 +47,21 @@ decoder_stream_decode(const struct decoder_plugin *plugin,
assert
(
decoder
->
decoder_tag
==
NULL
);
assert
(
input_stream
!=
NULL
);
assert
(
input_stream
->
ready
);
assert
(
d
c
.
state
==
DECODE_STATE_START
);
assert
(
d
ecoder
->
dc
->
state
==
DECODE_STATE_START
);
decoder_unlock
();
decoder_unlock
(
decoder
->
dc
);
/* rewind the stream, so each plugin gets a fresh start */
input_stream_seek
(
input_stream
,
0
,
SEEK_SET
);
decoder_plugin_stream_decode
(
plugin
,
decoder
,
input_stream
);
decoder_lock
();
decoder_lock
(
decoder
->
dc
);
assert
(
d
c
.
state
==
DECODE_STATE_START
||
d
c
.
state
==
DECODE_STATE_DECODE
);
assert
(
d
ecoder
->
dc
->
state
==
DECODE_STATE_START
||
d
ecoder
->
dc
->
state
==
DECODE_STATE_DECODE
);
return
d
c
.
state
!=
DECODE_STATE_START
;
return
d
ecoder
->
dc
->
state
!=
DECODE_STATE_START
;
}
static
bool
...
...
@@ -75,30 +75,34 @@ decoder_file_decode(const struct decoder_plugin *plugin,
assert
(
decoder
->
decoder_tag
==
NULL
);
assert
(
path
!=
NULL
);
assert
(
g_path_is_absolute
(
path
));
assert
(
d
c
.
state
==
DECODE_STATE_START
);
assert
(
d
ecoder
->
dc
->
state
==
DECODE_STATE_START
);
decoder_unlock
();
decoder_unlock
(
decoder
->
dc
);
decoder_plugin_file_decode
(
plugin
,
decoder
,
path
);
decoder_lock
();
decoder_lock
(
decoder
->
dc
);
assert
(
d
c
.
state
==
DECODE_STATE_START
||
d
c
.
state
==
DECODE_STATE_DECODE
);
assert
(
d
ecoder
->
dc
->
state
==
DECODE_STATE_START
||
d
ecoder
->
dc
->
state
==
DECODE_STATE_DECODE
);
return
d
c
.
state
!=
DECODE_STATE_START
;
return
d
ecoder
->
dc
->
state
!=
DECODE_STATE_START
;
}
static
void
decoder_run_song
(
const
struct
song
*
song
,
const
char
*
uri
)
static
void
decoder_run_song
(
struct
decoder_control
*
dc
,
const
struct
song
*
song
,
const
char
*
uri
)
{
struct
decoder
decoder
;
struct
decoder
decoder
=
{
.
dc
=
dc
,
};
int
ret
;
bool
close_instream
=
true
;
struct
input_stream
input_stream
;
const
struct
decoder_plugin
*
plugin
;
if
(
!
input_stream_open
(
&
input_stream
,
uri
))
{
dc
.
state
=
DECODE_STATE_ERROR
;
dc
->
state
=
DECODE_STATE_ERROR
;
return
;
}
...
...
@@ -109,8 +113,8 @@ static void decoder_run_song(const struct song *song, const char *uri)
decoder
.
decoder_tag
=
NULL
;
decoder
.
chunk
=
NULL
;
dc
.
state
=
DECODE_STATE_START
;
dc
.
command
=
DECODE_COMMAND_NONE
;
dc
->
state
=
DECODE_STATE_START
;
dc
->
command
=
DECODE_COMMAND_NONE
;
player_signal
();
...
...
@@ -118,32 +122,32 @@ static void decoder_run_song(const struct song *song, const char *uri)
will be available then */
while
(
!
input_stream
.
ready
)
{
if
(
dc
.
command
==
DECODE_COMMAND_STOP
)
{
decoder_unlock
();
if
(
dc
->
command
==
DECODE_COMMAND_STOP
)
{
decoder_unlock
(
dc
);
input_stream_close
(
&
input_stream
);
decoder_lock
();
dc
.
state
=
DECODE_STATE_STOP
;
decoder_lock
(
dc
);
dc
->
state
=
DECODE_STATE_STOP
;
return
;
}
decoder_unlock
();
decoder_unlock
(
dc
);
ret
=
input_stream_buffer
(
&
input_stream
);
if
(
ret
<
0
)
{
input_stream_close
(
&
input_stream
);
decoder_lock
();
dc
.
state
=
DECODE_STATE_ERROR
;
decoder_lock
(
dc
);
dc
->
state
=
DECODE_STATE_ERROR
;
return
;
}
decoder_lock
();
decoder_lock
(
dc
);
}
if
(
dc
.
command
==
DECODE_COMMAND_STOP
)
{
decoder_unlock
();
if
(
dc
->
command
==
DECODE_COMMAND_STOP
)
{
decoder_unlock
(
dc
);
input_stream_close
(
&
input_stream
);
decoder_lock
();
decoder_lock
(
dc
);
dc
.
state
=
DECODE_STATE_STOP
;
dc
->
state
=
DECODE_STATE_STOP
;
return
;
}
...
...
@@ -162,7 +166,7 @@ static void decoder_run_song(const struct song *song, const char *uri)
if
(
ret
)
break
;
assert
(
dc
.
state
==
DECODE_STATE_START
);
assert
(
dc
->
state
==
DECODE_STATE_START
);
}
/* if that fails, try suffix matching the URL: */
...
...
@@ -177,7 +181,7 @@ static void decoder_run_song(const struct song *song, const char *uri)
if
(
ret
)
break
;
assert
(
dc
.
state
==
DECODE_STATE_START
);
assert
(
dc
->
state
==
DECODE_STATE_START
);
}
}
/* fallback to mp3: */
...
...
@@ -196,9 +200,9 @@ static void decoder_run_song(const struct song *song, const char *uri)
const
char
*
s
=
uri_get_suffix
(
uri
);
while
((
plugin
=
decoder_plugin_from_suffix
(
s
,
next
++
)))
{
if
(
plugin
->
file_decode
!=
NULL
)
{
decoder_unlock
();
decoder_unlock
(
dc
);
input_stream_close
(
&
input_stream
);
decoder_lock
();
decoder_lock
(
dc
);
close_instream
=
false
;
ret
=
decoder_file_decode
(
plugin
,
...
...
@@ -213,9 +217,9 @@ static void decoder_run_song(const struct song *song, const char *uri)
reopen it */
bool
success
;
decoder_unlock
();
decoder_unlock
(
dc
);
success
=
input_stream_open
(
&
input_stream
,
uri
);
decoder_lock
();
decoder_lock
(
dc
);
if
(
success
)
close_instream
=
true
;
...
...
@@ -231,7 +235,7 @@ static void decoder_run_song(const struct song *song, const char *uri)
}
}
decoder_unlock
();
decoder_unlock
(
dc
);
pcm_convert_deinit
(
&
decoder
.
conv_state
);
...
...
@@ -251,14 +255,15 @@ static void decoder_run_song(const struct song *song, const char *uri)
if
(
decoder
.
decoder_tag
!=
NULL
)
tag_free
(
decoder
.
decoder_tag
);
decoder_lock
();
decoder_lock
(
dc
);
dc
.
state
=
ret
?
DECODE_STATE_STOP
:
DECODE_STATE_ERROR
;
dc
->
state
=
ret
?
DECODE_STATE_STOP
:
DECODE_STATE_ERROR
;
}
static
void
decoder_run
(
void
)
static
void
decoder_run
(
struct
decoder_control
*
dc
)
{
struct
song
*
song
=
dc
.
next_song
;
struct
song
*
song
=
dc
->
next_song
;
char
*
uri
;
if
(
song_is_file
(
song
))
...
...
@@ -267,58 +272,62 @@ static void decoder_run(void)
uri
=
song_get_uri
(
song
);
if
(
uri
==
NULL
)
{
dc
.
state
=
DECODE_STATE_ERROR
;
dc
->
state
=
DECODE_STATE_ERROR
;
return
;
}
dc
.
current_song
=
dc
.
next_song
;
/* NEED LOCK */
decoder_run_song
(
song
,
uri
);
dc
->
current_song
=
dc
->
next_song
;
/* NEED LOCK */
decoder_run_song
(
dc
,
song
,
uri
);
g_free
(
uri
);
}
static
gpointer
decoder_task
(
G_GNUC_UNUSED
gpointer
arg
)
static
gpointer
decoder_task
(
gpointer
arg
)
{
decoder_lock
();
struct
decoder_control
*
dc
=
arg
;
decoder_lock
(
dc
);
do
{
assert
(
dc
.
state
==
DECODE_STATE_STOP
||
dc
.
state
==
DECODE_STATE_ERROR
);
assert
(
dc
->
state
==
DECODE_STATE_STOP
||
dc
->
state
==
DECODE_STATE_ERROR
);
switch
(
dc
.
command
)
{
switch
(
dc
->
command
)
{
case
DECODE_COMMAND_START
:
case
DECODE_COMMAND_SEEK
:
decoder_run
();
decoder_run
(
dc
);
dc
.
command
=
DECODE_COMMAND_NONE
;
dc
->
command
=
DECODE_COMMAND_NONE
;
player_signal
();
break
;
case
DECODE_COMMAND_STOP
:
dc
.
command
=
DECODE_COMMAND_NONE
;
dc
->
command
=
DECODE_COMMAND_NONE
;
player_signal
();
break
;
case
DECODE_COMMAND_NONE
:
decoder_wait
();
decoder_wait
(
dc
);
break
;
}
}
while
(
dc
.
command
!=
DECODE_COMMAND_NONE
||
!
dc
.
quit
);
}
while
(
dc
->
command
!=
DECODE_COMMAND_NONE
||
!
dc
->
quit
);
decoder_unlock
();
decoder_unlock
(
dc
);
return
NULL
;
}
void
decoder_thread_start
(
void
)
void
decoder_thread_start
(
struct
decoder_control
*
dc
)
{
GError
*
e
=
NULL
;
assert
(
dc
.
thread
==
NULL
);
assert
(
dc
->
thread
==
NULL
);
dc
.
thread
=
g_thread_create
(
decoder_task
,
NULL
,
true
,
&
e
);
if
(
dc
.
thread
==
NULL
)
dc
->
thread
=
g_thread_create
(
decoder_task
,
dc
,
true
,
&
e
);
if
(
dc
->
thread
==
NULL
)
g_error
(
"Failed to spawn decoder task: %s"
,
e
->
message
);
}
src/decoder_thread.h
View file @
6ef428af
...
...
@@ -20,6 +20,9 @@
#ifndef MPD_DECODER_THREAD_H
#define MPD_DECODER_THREAD_H
void
decoder_thread_start
(
void
);
struct
decoder_control
;
void
decoder_thread_start
(
struct
decoder_control
*
dc
);
#endif
src/main.c
View file @
6ef428af
...
...
@@ -33,7 +33,6 @@
#include "path.h"
#include "mapper.h"
#include "chunk.h"
#include "decoder_control.h"
#include "player_control.h"
#include "stats.h"
#include "sig_handlers.h"
...
...
@@ -254,7 +253,6 @@ initialize_decoder_and_player(void)
buffered_before_play
=
buffered_chunks
;
pc_init
(
buffered_chunks
,
buffered_before_play
);
dc_init
();
}
/**
...
...
@@ -426,7 +424,6 @@ int main(int argc, char *argv[])
mapper_finish
();
path_global_finish
();
finishPermissions
();
dc_deinit
();
pc_deinit
();
command_finish
();
update_global_finish
();
...
...
src/player_control.c
View file @
6ef428af
...
...
@@ -53,11 +53,11 @@ void pc_deinit(void)
}
void
player_wait_decoder
(
void
)
player_wait_decoder
(
struct
decoder_control
*
dc
)
{
/* during this function, the decoder lock is held, because
we're waiting for the decoder thread */
g_cond_wait
(
pc
.
cond
,
dc
.
mutex
);
g_cond_wait
(
pc
.
cond
,
dc
->
mutex
);
}
void
...
...
src/player_control.h
View file @
6ef428af
...
...
@@ -25,6 +25,8 @@
#include <stdint.h>
struct
decoder_control
;
enum
player_state
{
PLAYER_STATE_STOP
=
0
,
PLAYER_STATE_PAUSE
,
...
...
@@ -155,7 +157,7 @@ player_wait(void)
* Note the small difference to the player_wait() function!
*/
void
player_wait_decoder
(
void
);
player_wait_decoder
(
struct
decoder_control
*
dc
);
/**
* Signals the #player_control object. The object should be locked
...
...
src/player_thread.c
View file @
6ef428af
...
...
@@ -46,6 +46,8 @@ enum xfade_state {
};
struct
player
{
struct
decoder_control
*
dc
;
struct
music_pipe
*
pipe
;
/**
...
...
@@ -129,17 +131,19 @@ static void player_command_finished(void)
static
void
player_dc_stop
(
struct
player
*
player
)
{
dc_stop
();
struct
decoder_control
*
dc
=
player
->
dc
;
dc_stop
(
dc
);
if
(
dc
.
pipe
!=
NULL
)
{
if
(
dc
->
pipe
!=
NULL
)
{
/* clear and free the decoder pipe */
music_pipe_clear
(
dc
.
pipe
,
player_buffer
);
music_pipe_clear
(
dc
->
pipe
,
player_buffer
);
if
(
dc
.
pipe
!=
player
->
pipe
)
music_pipe_free
(
dc
.
pipe
);
if
(
dc
->
pipe
!=
player
->
pipe
)
music_pipe_free
(
dc
->
pipe
);
dc
.
pipe
=
NULL
;
dc
->
pipe
=
NULL
;
}
}
...
...
@@ -153,13 +157,15 @@ player_dc_stop(struct player *player)
static
bool
player_wait_for_decoder
(
struct
player
*
player
)
{
dc_command_wait
();
struct
decoder_control
*
dc
=
player
->
dc
;
dc_command_wait
(
dc
);
if
(
decoder_lock_has_failed
())
{
assert
(
dc
.
next_song
==
NULL
||
dc
.
next_song
->
uri
!=
NULL
);
if
(
decoder_lock_has_failed
(
dc
))
{
assert
(
dc
->
next_song
==
NULL
||
dc
->
next_song
->
uri
!=
NULL
);
player_lock
();
pc
.
errored_song
=
dc
.
next_song
;
pc
.
errored_song
=
dc
->
next_song
;
pc
.
error
=
PLAYER_ERROR_FILE
;
pc
.
next_song
=
NULL
;
player_unlock
();
...
...
@@ -198,24 +204,26 @@ player_wait_for_decoder(struct player *player)
static
bool
player_check_decoder_startup
(
struct
player
*
player
)
{
struct
decoder_control
*
dc
=
player
->
dc
;
assert
(
player
->
decoder_starting
);
decoder_lock
();
decoder_lock
(
dc
);
if
(
decoder_has_failed
())
{
if
(
decoder_has_failed
(
dc
))
{
/* the decoder failed */
assert
(
dc
.
next_song
==
NULL
||
dc
.
next_song
->
uri
!=
NULL
);
assert
(
dc
->
next_song
==
NULL
||
dc
->
next_song
->
uri
!=
NULL
);
decoder_unlock
();
decoder_unlock
(
dc
);
pc
.
errored_song
=
dc
.
next_song
;
pc
.
errored_song
=
dc
->
next_song
;
pc
.
error
=
PLAYER_ERROR_FILE
;
return
false
;
}
else
if
(
!
decoder_is_starting
())
{
}
else
if
(
!
decoder_is_starting
(
dc
))
{
/* the decoder is ready and ok */
decoder_unlock
();
decoder_unlock
(
dc
);
if
(
audio_format_defined
(
&
player
->
play_audio_format
)
&&
!
audio_output_all_wait
(
1
))
...
...
@@ -223,21 +231,21 @@ player_check_decoder_startup(struct player *player)
all chunks yet - wait for that */
return
true
;
pc
.
total_time
=
dc
.
total_time
;
pc
.
audio_format
=
dc
.
in_audio_format
;
player
->
play_audio_format
=
dc
.
out_audio_format
;
pc
.
total_time
=
dc
->
total_time
;
pc
.
audio_format
=
dc
->
in_audio_format
;
player
->
play_audio_format
=
dc
->
out_audio_format
;
player
->
decoder_starting
=
false
;
if
(
!
player
->
paused
&&
!
audio_output_all_open
(
&
dc
.
out_audio_format
,
!
audio_output_all_open
(
&
dc
->
out_audio_format
,
player_buffer
))
{
char
*
uri
=
song_get_uri
(
dc
.
next_song
);
char
*
uri
=
song_get_uri
(
dc
->
next_song
);
g_warning
(
"problems opening audio device "
"while playing
\"
%s
\"
"
,
uri
);
g_free
(
uri
);
assert
(
dc
.
next_song
==
NULL
||
dc
.
next_song
->
uri
!=
NULL
);
pc
.
errored_song
=
dc
.
next_song
;
assert
(
dc
->
next_song
==
NULL
||
dc
->
next_song
->
uri
!=
NULL
);
pc
.
errored_song
=
dc
->
next_song
;
pc
.
error
=
PLAYER_ERROR_AUDIO
;
/* pause: the user may resume playback as soon
...
...
@@ -251,8 +259,8 @@ player_check_decoder_startup(struct player *player)
}
else
{
/* the decoder is not yet ready; wait
some more */
player_wait_decoder
();
decoder_unlock
();
player_wait_decoder
(
dc
);
decoder_unlock
(
dc
);
return
true
;
}
...
...
@@ -305,12 +313,13 @@ player_send_silence(struct player *player)
*/
static
bool
player_seek_decoder
(
struct
player
*
player
)
{
struct
decoder_control
*
dc
=
player
->
dc
;
double
where
;
bool
ret
;
assert
(
pc
.
next_song
!=
NULL
);
if
(
decoder_current_song
()
!=
pc
.
next_song
)
{
if
(
decoder_current_song
(
dc
)
!=
pc
.
next_song
)
{
/* the decoder is already decoding the "next" song -
stop it and start the previous song again */
...
...
@@ -319,10 +328,10 @@ static bool player_seek_decoder(struct player *player)
/* clear music chunks which might still reside in the
pipe */
music_pipe_clear
(
player
->
pipe
,
player_buffer
);
dc
.
pipe
=
player
->
pipe
;
dc
->
pipe
=
player
->
pipe
;
/* re-start the decoder */
dc_start_async
(
pc
.
next_song
);
dc_start_async
(
dc
,
pc
.
next_song
);
ret
=
player_wait_for_decoder
(
player
);
if
(
!
ret
)
{
/* decoder failure */
...
...
@@ -353,7 +362,7 @@ static bool player_seek_decoder(struct player *player)
if
(
where
<
0
.
0
)
where
=
0
.
0
;
ret
=
dc_seek
(
where
);
ret
=
dc_seek
(
dc
,
where
);
if
(
!
ret
)
{
/* decoder failure */
player_command_finished
();
...
...
@@ -379,6 +388,8 @@ static bool player_seek_decoder(struct player *player)
*/
static
void
player_process_command
(
struct
player
*
player
)
{
struct
decoder_control
*
dc
=
player
->
dc
;
switch
(
pc
.
command
)
{
case
PLAYER_COMMAND_NONE
:
case
PLAYER_COMMAND_STOP
:
...
...
@@ -396,7 +407,7 @@ static void player_process_command(struct player *player)
case
PLAYER_COMMAND_QUEUE
:
assert
(
pc
.
next_song
!=
NULL
);
assert
(
!
player
->
queued
);
assert
(
dc
.
pipe
==
NULL
||
dc
.
pipe
==
player
->
pipe
);
assert
(
dc
->
pipe
==
NULL
||
dc
->
pipe
==
player
->
pipe
);
player
->
queued
=
true
;
player_command_finished_locked
();
...
...
@@ -425,8 +436,8 @@ static void player_process_command(struct player *player)
}
else
{
/* the audio device has failed - rollback to
pause mode */
assert
(
dc
.
next_song
==
NULL
||
dc
.
next_song
->
uri
!=
NULL
);
pc
.
errored_song
=
dc
.
next_song
;
assert
(
dc
->
next_song
==
NULL
||
dc
->
next_song
->
uri
!=
NULL
);
pc
.
errored_song
=
dc
->
next_song
;
pc
.
error
=
PLAYER_ERROR_AUDIO
;
player
->
paused
=
true
;
...
...
@@ -452,7 +463,7 @@ static void player_process_command(struct player *player)
return
;
}
if
(
dc
.
pipe
!=
NULL
&&
dc
.
pipe
!=
player
->
pipe
)
{
if
(
dc
->
pipe
!=
NULL
&&
dc
->
pipe
!=
player
->
pipe
)
{
/* the decoder is already decoding the song -
stop it and reset the position */
player_unlock
();
...
...
@@ -549,6 +560,7 @@ play_chunk(struct song *song, struct music_chunk *chunk,
static
bool
play_next_chunk
(
struct
player
*
player
)
{
struct
decoder_control
*
dc
=
player
->
dc
;
struct
music_chunk
*
chunk
=
NULL
;
unsigned
cross_fade_position
;
bool
success
;
...
...
@@ -559,12 +571,12 @@ play_next_chunk(struct player *player)
return
true
;
if
(
player
->
xfade
==
XFADE_ENABLED
&&
dc
.
pipe
!=
NULL
&&
dc
.
pipe
!=
player
->
pipe
&&
dc
->
pipe
!=
NULL
&&
dc
->
pipe
!=
player
->
pipe
&&
(
cross_fade_position
=
music_pipe_size
(
player
->
pipe
))
<=
player
->
cross_fade_chunks
)
{
/* perform cross fade */
struct
music_chunk
*
other_chunk
=
music_pipe_shift
(
dc
.
pipe
);
music_pipe_shift
(
dc
->
pipe
);
if
(
!
player
->
cross_fading
)
{
/* beginning of the cross fade - adjust
...
...
@@ -580,26 +592,26 @@ play_next_chunk(struct player *player)
assert
(
chunk
!=
NULL
);
cross_fade_apply
(
chunk
,
other_chunk
,
&
dc
.
out_audio_format
,
&
dc
->
out_audio_format
,
cross_fade_position
,
player
->
cross_fade_chunks
);
music_buffer_return
(
player_buffer
,
other_chunk
);
}
else
{
/* there are not enough decoded chunks yet */
decoder_lock
();
decoder_lock
(
dc
);
if
(
decoder_is_idle
())
{
if
(
decoder_is_idle
(
dc
))
{
/* the decoder isn't running, abort
cross fading */
decoder_unlock
();
decoder_unlock
(
dc
);
player
->
xfade
=
XFADE_DISABLED
;
}
else
{
/* wait for the decoder */
decoder_signal
();
player_wait_decoder
();
decoder_unlock
();
decoder_signal
(
dc
);
player_wait_decoder
(
dc
);
decoder_unlock
(
dc
);
return
true
;
}
...
...
@@ -635,12 +647,12 @@ play_next_chunk(struct player *player)
/* this formula should prevent that the decoder gets woken up
with each chunk; it is more efficient to make it decode a
larger block at a time */
decoder_lock
();
if
(
!
decoder_is_idle
()
&&
music_pipe_size
(
dc
.
pipe
)
<=
(
pc
.
buffered_before_play
+
decoder_lock
(
dc
);
if
(
!
decoder_is_idle
(
dc
)
&&
music_pipe_size
(
dc
->
pipe
)
<=
(
pc
.
buffered_before_play
+
music_buffer_size
(
player_buffer
)
*
3
)
/
4
)
decoder_signal
();
decoder_unlock
();
decoder_signal
(
dc
);
decoder_unlock
(
dc
);
return
true
;
}
...
...
@@ -666,7 +678,7 @@ player_song_border(struct player *player)
g_free
(
uri
);
music_pipe_free
(
player
->
pipe
);
player
->
pipe
=
dc
.
pipe
;
player
->
pipe
=
player
->
dc
->
pipe
;
if
(
!
player_wait_for_decoder
(
player
))
return
false
;
...
...
@@ -679,9 +691,10 @@ player_song_border(struct player *player)
* basically a state machine, which multiplexes data between the
* decoder thread and the output threads.
*/
static
void
do_play
(
void
)
static
void
do_play
(
struct
decoder_control
*
dc
)
{
struct
player
player
=
{
.
dc
=
dc
,
.
buffering
=
true
,
.
decoder_starting
=
false
,
.
paused
=
false
,
...
...
@@ -697,9 +710,9 @@ static void do_play(void)
player
.
pipe
=
music_pipe_new
();
dc
.
buffer
=
player_buffer
;
dc
.
pipe
=
player
.
pipe
;
dc_start
(
pc
.
next_song
);
dc
->
buffer
=
player_buffer
;
dc
->
pipe
=
player
.
pipe
;
dc_start
(
dc
,
pc
.
next_song
);
if
(
!
player_wait_for_decoder
(
&
player
))
{
player_dc_stop
(
&
player
);
player_command_finished
();
...
...
@@ -731,7 +744,7 @@ static void do_play(void)
prevent stuttering on slow machines */
if
(
music_pipe_size
(
player
.
pipe
)
<
pc
.
buffered_before_play
&&
!
decoder_lock_is_idle
())
{
!
decoder_lock_is_idle
(
dc
))
{
/* not enough decoded buffer space yet */
if
(
!
player
.
paused
&&
...
...
@@ -740,10 +753,10 @@ static void do_play(void)
!
player_send_silence
(
&
player
))
break
;
decoder_lock
();
decoder_lock
(
dc
);
/* XXX race condition: check decoder again */
player_wait_decoder
();
decoder_unlock
();
player_wait_decoder
(
dc
);
decoder_unlock
(
dc
);
player_lock
();
continue
;
}
else
{
...
...
@@ -768,30 +781,30 @@ static void do_play(void)
/*
music_pipe_check_format(&play_audio_format,
player.next_song_chunk,
&dc
.
out_audio_format);
&dc
->
out_audio_format);
*/
#endif
if
(
decoder_lock_is_idle
()
&&
player
.
queued
)
{
if
(
decoder_lock_is_idle
(
dc
)
&&
player
.
queued
)
{
/* the decoder has finished the current song;
make it decode the next song */
assert
(
pc
.
next_song
!=
NULL
);
assert
(
dc
.
pipe
==
NULL
||
dc
.
pipe
==
player
.
pipe
);
assert
(
dc
->
pipe
==
NULL
||
dc
->
pipe
==
player
.
pipe
);
player
.
queued
=
false
;
dc
.
pipe
=
music_pipe_new
();
dc_start_async
(
pc
.
next_song
);
dc
->
pipe
=
music_pipe_new
();
dc_start_async
(
dc
,
pc
.
next_song
);
}
if
(
dc
.
pipe
!=
NULL
&&
dc
.
pipe
!=
player
.
pipe
&&
if
(
dc
->
pipe
!=
NULL
&&
dc
->
pipe
!=
player
.
pipe
&&
player
.
xfade
==
XFADE_UNKNOWN
&&
!
decoder_lock_is_starting
())
{
!
decoder_lock_is_starting
(
dc
))
{
/* enable cross fading in this song? if yes,
calculate how many chunks will be required
for it */
player
.
cross_fade_chunks
=
cross_fade_calc
(
pc
.
cross_fade_seconds
,
dc
.
total_time
,
&
dc
.
out_audio_format
,
cross_fade_calc
(
pc
.
cross_fade_seconds
,
dc
->
total_time
,
&
dc
->
out_audio_format
,
&
player
.
play_audio_format
,
music_buffer_size
(
player_buffer
)
-
pc
.
buffered_before_play
);
...
...
@@ -820,12 +833,12 @@ static void do_play(void)
/* XXX synchronize in a better way */
g_usleep
(
10000
);
}
else
if
(
dc
.
pipe
!=
NULL
&&
dc
.
pipe
!=
player
.
pipe
)
{
}
else
if
(
dc
->
pipe
!=
NULL
&&
dc
->
pipe
!=
player
.
pipe
)
{
/* at the beginning of a new song */
if
(
!
player_song_border
(
&
player
))
break
;
}
else
if
(
decoder_lock_is_idle
())
{
}
else
if
(
decoder_lock_is_idle
(
dc
))
{
/* check the size of the pipe again, because
the decoder thread may have added something
since we last checked */
...
...
@@ -861,7 +874,10 @@ static void do_play(void)
static
gpointer
player_task
(
G_GNUC_UNUSED
gpointer
arg
)
{
decoder_thread_start
();
struct
decoder_control
dc
;
dc_init
(
&
dc
);
decoder_thread_start
(
&
dc
);
player_buffer
=
music_buffer_new
(
pc
.
buffer_chunks
);
...
...
@@ -872,7 +888,7 @@ static gpointer player_task(G_GNUC_UNUSED gpointer arg)
case
PLAYER_COMMAND_QUEUE
:
assert
(
pc
.
next_song
!=
NULL
);
do_play
();
do_play
(
&
dc
);
break
;
case
PLAYER_COMMAND_STOP
:
...
...
@@ -916,7 +932,8 @@ static gpointer player_task(G_GNUC_UNUSED gpointer arg)
case
PLAYER_COMMAND_EXIT
:
player_unlock
();
dc_quit
();
dc_quit
(
&
dc
);
dc_deinit
(
&
dc
);
audio_output_all_close
();
music_buffer_free
(
player_buffer
);
...
...
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