player_control: removed the global variable "pc"
Allocate a player_control object where needed, and pass it around. Each "client" object is associated with a "player_control" instance. This prepares multi-player support.
This commit is contained in:
parent
715844fd08
commit
b6995ca011
@ -27,11 +27,13 @@
|
|||||||
|
|
||||||
struct client;
|
struct client;
|
||||||
struct sockaddr;
|
struct sockaddr;
|
||||||
|
struct player_control;
|
||||||
|
|
||||||
void client_manager_init(void);
|
void client_manager_init(void);
|
||||||
void client_manager_deinit(void);
|
void client_manager_deinit(void);
|
||||||
|
|
||||||
void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid);
|
void client_new(struct player_control *player_control,
|
||||||
|
int fd, const struct sockaddr *sa, size_t sa_length, int uid);
|
||||||
|
|
||||||
bool client_is_expired(const struct client *client);
|
bool client_is_expired(const struct client *client);
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ struct deferred_buffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct client {
|
struct client {
|
||||||
|
struct player_control *player_control;
|
||||||
|
|
||||||
GIOChannel *channel;
|
GIOChannel *channel;
|
||||||
guint source_id;
|
guint source_id;
|
||||||
|
|
||||||
|
@ -41,12 +41,15 @@
|
|||||||
|
|
||||||
static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n";
|
static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n";
|
||||||
|
|
||||||
void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
|
void
|
||||||
|
client_new(struct player_control *player_control,
|
||||||
|
int fd, const struct sockaddr *sa, size_t sa_length, int uid)
|
||||||
{
|
{
|
||||||
static unsigned int next_client_num;
|
static unsigned int next_client_num;
|
||||||
struct client *client;
|
struct client *client;
|
||||||
char *remote;
|
char *remote;
|
||||||
|
|
||||||
|
assert(player_control != NULL);
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
|
|
||||||
#ifdef HAVE_LIBWRAP
|
#ifdef HAVE_LIBWRAP
|
||||||
@ -81,6 +84,7 @@ void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
client = g_new0(struct client, 1);
|
client = g_new0(struct client, 1);
|
||||||
|
client->player_control = player_control;
|
||||||
|
|
||||||
#ifndef G_OS_WIN32
|
#ifndef G_OS_WIN32
|
||||||
client->channel = g_io_channel_unix_new(fd);
|
client->channel = g_io_channel_unix_new(fd);
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "dbUtils.h"
|
#include "dbUtils.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
#include "client_internal.h"
|
||||||
#include "tag_print.h"
|
#include "tag_print.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "replay_gain_config.h"
|
#include "replay_gain_config.h"
|
||||||
@ -434,7 +435,7 @@ handle_play(struct client *client, int argc, char *argv[])
|
|||||||
|
|
||||||
if (argc == 2 && !check_int(client, &song, argv[1], need_positive))
|
if (argc == 2 && !check_int(client, &song, argv[1], need_positive))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_play(&g_playlist, song);
|
result = playlist_play(&g_playlist, client->player_control, song);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,7 +448,7 @@ handle_playid(struct client *client, int argc, char *argv[])
|
|||||||
if (argc == 2 && !check_int(client, &id, argv[1], need_positive))
|
if (argc == 2 && !check_int(client, &id, argv[1], need_positive))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_play_id(&g_playlist, id);
|
result = playlist_play_id(&g_playlist, client->player_control, id);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,7 +456,7 @@ static enum command_return
|
|||||||
handle_stop(G_GNUC_UNUSED struct client *client,
|
handle_stop(G_GNUC_UNUSED struct client *client,
|
||||||
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
||||||
{
|
{
|
||||||
playlist_stop(&g_playlist);
|
playlist_stop(&g_playlist, client->player_control);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,9 +477,9 @@ handle_pause(struct client *client,
|
|||||||
if (!check_bool(client, &pause_flag, argv[1]))
|
if (!check_bool(client, &pause_flag, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
pc_set_pause(pause_flag);
|
pc_set_pause(client->player_control, pause_flag);
|
||||||
} else
|
} else
|
||||||
pc_pause();
|
pc_pause(client->player_control);
|
||||||
|
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
@ -493,7 +494,7 @@ handle_status(struct client *client,
|
|||||||
char *error;
|
char *error;
|
||||||
int song;
|
int song;
|
||||||
|
|
||||||
pc_get_status(&player_status);
|
pc_get_status(client->player_control, &player_status);
|
||||||
|
|
||||||
switch (player_status.state) {
|
switch (player_status.state) {
|
||||||
case PLAYER_STATE_STOP:
|
case PLAYER_STATE_STOP:
|
||||||
@ -526,9 +527,9 @@ handle_status(struct client *client,
|
|||||||
playlist_get_consume(&g_playlist),
|
playlist_get_consume(&g_playlist),
|
||||||
playlist_get_version(&g_playlist),
|
playlist_get_version(&g_playlist),
|
||||||
playlist_get_length(&g_playlist),
|
playlist_get_length(&g_playlist),
|
||||||
(int)(pc_get_cross_fade() + 0.5),
|
(int)(pc_get_cross_fade(client->player_control) + 0.5),
|
||||||
pc_get_mixramp_db(),
|
pc_get_mixramp_db(client->player_control),
|
||||||
pc_get_mixramp_delay(),
|
pc_get_mixramp_delay(client->player_control),
|
||||||
state);
|
state);
|
||||||
|
|
||||||
song = playlist_get_current_song(&g_playlist);
|
song = playlist_get_current_song(&g_playlist);
|
||||||
@ -561,7 +562,7 @@ handle_status(struct client *client,
|
|||||||
updateJobId);
|
updateJobId);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = pc_get_error_message();
|
error = pc_get_error_message(client->player_control);
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
client_printf(client,
|
client_printf(client,
|
||||||
COMMAND_STATUS_ERROR ": %s\n",
|
COMMAND_STATUS_ERROR ": %s\n",
|
||||||
@ -605,6 +606,7 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
result = PLAYLIST_RESULT_DENIED;
|
result = PLAYLIST_RESULT_DENIED;
|
||||||
#else
|
#else
|
||||||
result = playlist_append_file(&g_playlist,
|
result = playlist_append_file(&g_playlist,
|
||||||
|
client->player_control,
|
||||||
uri + 7, client_get_uid(client),
|
uri + 7, client_get_uid(client),
|
||||||
NULL);
|
NULL);
|
||||||
#endif
|
#endif
|
||||||
@ -618,11 +620,13 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = playlist_append_uri(&g_playlist, uri, NULL);
|
result = playlist_append_uri(&g_playlist,
|
||||||
|
client->player_control,
|
||||||
|
uri, NULL);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = addAllIn(uri);
|
result = addAllIn(client->player_control, uri);
|
||||||
if (result == (enum playlist_result)-1) {
|
if (result == (enum playlist_result)-1) {
|
||||||
command_error(client, ACK_ERROR_NO_EXIST,
|
command_error(client, ACK_ERROR_NO_EXIST,
|
||||||
"directory or file not found");
|
"directory or file not found");
|
||||||
@ -643,7 +647,9 @@ handle_addid(struct client *client, int argc, char *argv[])
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
result = PLAYLIST_RESULT_DENIED;
|
result = PLAYLIST_RESULT_DENIED;
|
||||||
#else
|
#else
|
||||||
result = playlist_append_file(&g_playlist, uri + 7,
|
result = playlist_append_file(&g_playlist,
|
||||||
|
client->player_control,
|
||||||
|
uri + 7,
|
||||||
client_get_uid(client),
|
client_get_uid(client),
|
||||||
&added_id);
|
&added_id);
|
||||||
#endif
|
#endif
|
||||||
@ -654,7 +660,9 @@ handle_addid(struct client *client, int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = playlist_append_uri(&g_playlist, uri, &added_id);
|
result = playlist_append_uri(&g_playlist,
|
||||||
|
client->player_control,
|
||||||
|
uri, &added_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS)
|
if (result != PLAYLIST_RESULT_SUCCESS)
|
||||||
@ -664,11 +672,13 @@ handle_addid(struct client *client, int argc, char *argv[])
|
|||||||
int to;
|
int to;
|
||||||
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
|
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_move_id(&g_playlist, added_id, to);
|
result = playlist_move_id(&g_playlist, client->player_control,
|
||||||
|
added_id, to);
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS) {
|
if (result != PLAYLIST_RESULT_SUCCESS) {
|
||||||
enum command_return ret =
|
enum command_return ret =
|
||||||
print_playlist_result(client, result);
|
print_playlist_result(client, result);
|
||||||
playlist_delete_id(&g_playlist, added_id);
|
playlist_delete_id(&g_playlist, client->player_control,
|
||||||
|
added_id);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -686,7 +696,8 @@ handle_delete(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!check_range(client, &start, &end, argv[1], need_range))
|
if (!check_range(client, &start, &end, argv[1], need_range))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_delete_range(&g_playlist, start, end);
|
result = playlist_delete_range(&g_playlist, client->player_control,
|
||||||
|
start, end);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,7 +710,7 @@ handle_deleteid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!check_int(client, &id, argv[1], need_positive))
|
if (!check_int(client, &id, argv[1], need_positive))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_delete_id(&g_playlist, id);
|
result = playlist_delete_id(&g_playlist, client->player_control, id);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,7 +731,7 @@ handle_shuffle(G_GNUC_UNUSED struct client *client,
|
|||||||
argv[1], need_range))
|
argv[1], need_range))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
playlist_shuffle(&g_playlist, start, end);
|
playlist_shuffle(&g_playlist, client->player_control, start, end);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,7 +739,7 @@ static enum command_return
|
|||||||
handle_clear(G_GNUC_UNUSED struct client *client,
|
handle_clear(G_GNUC_UNUSED struct client *client,
|
||||||
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
||||||
{
|
{
|
||||||
playlist_clear(&g_playlist);
|
playlist_clear(&g_playlist, client->player_control);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,11 +758,13 @@ handle_load(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
enum playlist_result result;
|
enum playlist_result result;
|
||||||
|
|
||||||
result = playlist_open_into_queue(argv[1], &g_playlist, true);
|
result = playlist_open_into_queue(argv[1], &g_playlist,
|
||||||
|
client->player_control, true);
|
||||||
if (result != PLAYLIST_RESULT_NO_SUCH_LIST)
|
if (result != PLAYLIST_RESULT_NO_SUCH_LIST)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = playlist_load_spl(&g_playlist, argv[1]);
|
result = playlist_load_spl(&g_playlist, client->player_control,
|
||||||
|
argv[1]);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1141,7 +1154,7 @@ handle_next(G_GNUC_UNUSED struct client *client,
|
|||||||
int single = g_playlist.queue.single;
|
int single = g_playlist.queue.single;
|
||||||
g_playlist.queue.single = false;
|
g_playlist.queue.single = false;
|
||||||
|
|
||||||
playlist_next(&g_playlist);
|
playlist_next(&g_playlist, client->player_control);
|
||||||
|
|
||||||
g_playlist.queue.single = single;
|
g_playlist.queue.single = single;
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
@ -1151,7 +1164,7 @@ static enum command_return
|
|||||||
handle_previous(G_GNUC_UNUSED struct client *client,
|
handle_previous(G_GNUC_UNUSED struct client *client,
|
||||||
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
||||||
{
|
{
|
||||||
playlist_previous(&g_playlist);
|
playlist_previous(&g_playlist, client->player_control);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1210,7 +1223,7 @@ handle_repeat(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_set_repeat(&g_playlist, status);
|
playlist_set_repeat(&g_playlist, client->player_control, status);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1228,7 +1241,7 @@ handle_single(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_set_single(&g_playlist, status);
|
playlist_set_single(&g_playlist, client->player_control, status);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1264,7 +1277,7 @@ handle_random(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_set_random(&g_playlist, status);
|
playlist_set_random(&g_playlist, client->player_control, status);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,7 +1292,7 @@ static enum command_return
|
|||||||
handle_clearerror(G_GNUC_UNUSED struct client *client,
|
handle_clearerror(G_GNUC_UNUSED struct client *client,
|
||||||
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
||||||
{
|
{
|
||||||
pc_clear_error();
|
pc_clear_error(client->player_control);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1348,7 +1361,8 @@ handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
|
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_move_range(&g_playlist, start, end, to);
|
result = playlist_move_range(&g_playlist, client->player_control,
|
||||||
|
start, end, to);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1362,7 +1376,8 @@ handle_moveid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
|
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_move_id(&g_playlist, id, to);
|
result = playlist_move_id(&g_playlist, client->player_control,
|
||||||
|
id, to);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1376,7 +1391,8 @@ handle_swap(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_int(client, &song2, argv[2], check_integer, argv[2]))
|
if (!check_int(client, &song2, argv[2], check_integer, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_swap_songs(&g_playlist, song1, song2);
|
result = playlist_swap_songs(&g_playlist, client->player_control,
|
||||||
|
song1, song2);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1390,7 +1406,8 @@ handle_swapid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_int(client, &id2, argv[2], check_integer, argv[2]))
|
if (!check_int(client, &id2, argv[2], check_integer, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_swap_songs_id(&g_playlist, id1, id2);
|
result = playlist_swap_songs_id(&g_playlist, client->player_control,
|
||||||
|
id1, id2);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1405,7 +1422,8 @@ handle_seek(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
|
if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_seek_song(&g_playlist, song, seek_time);
|
result = playlist_seek_song(&g_playlist, client->player_control,
|
||||||
|
song, seek_time);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1420,7 +1438,8 @@ handle_seekid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
|
if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_seek_song_id(&g_playlist, id, seek_time);
|
result = playlist_seek_song_id(&g_playlist, client->player_control,
|
||||||
|
id, seek_time);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1470,7 +1489,7 @@ handle_crossfade(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
|
|
||||||
if (!check_unsigned(client, &xfade_time, argv[1]))
|
if (!check_unsigned(client, &xfade_time, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
pc_set_cross_fade(xfade_time);
|
pc_set_cross_fade(client->player_control, xfade_time);
|
||||||
|
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
@ -1482,7 +1501,7 @@ handle_mixrampdb(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
|
|
||||||
if (!check_float(client, &db, argv[1]))
|
if (!check_float(client, &db, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
pc_set_mixramp_db(db);
|
pc_set_mixramp_db(client->player_control, db);
|
||||||
|
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
@ -1494,7 +1513,7 @@ handle_mixrampdelay(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
|
|
||||||
if (!check_float(client, &delay_secs, argv[1]))
|
if (!check_float(client, &delay_secs, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
pc_set_mixramp_delay(delay_secs);
|
pc_set_mixramp_delay(client->player_control, delay_secs);
|
||||||
|
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "strset.h"
|
#include "strset.h"
|
||||||
#include "stored_playlist.h"
|
#include "stored_playlist.h"
|
||||||
|
#include "client_internal.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
@ -166,9 +167,11 @@ int printAllIn(struct client *client, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
directoryAddSongToPlaylist(struct song *song, G_GNUC_UNUSED void *data)
|
directoryAddSongToPlaylist(struct song *song, void *data)
|
||||||
{
|
{
|
||||||
return playlist_append_song(&g_playlist, song, NULL);
|
struct player_control *pc = data;
|
||||||
|
|
||||||
|
return playlist_append_song(&g_playlist, pc, song, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct add_data {
|
struct add_data {
|
||||||
@ -185,9 +188,10 @@ directoryAddSongToStoredPlaylist(struct song *song, void *_data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int addAllIn(const char *name)
|
int
|
||||||
|
addAllIn(struct player_control *pc, const char *name)
|
||||||
{
|
{
|
||||||
return db_walk(name, directoryAddSongToPlaylist, NULL, NULL);
|
return db_walk(name, directoryAddSongToPlaylist, NULL, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int addAllInToStoredPlaylist(const char *name, const char *utf8file)
|
int addAllInToStoredPlaylist(const char *name, const char *utf8file)
|
||||||
@ -205,7 +209,9 @@ findAddInDirectory(struct song *song, void *_data)
|
|||||||
struct search_data *data = _data;
|
struct search_data *data = _data;
|
||||||
|
|
||||||
if (locate_song_match(song, data->criteria))
|
if (locate_song_match(song, data->criteria))
|
||||||
return playlist_append_song(&g_playlist, song, NULL);
|
return playlist_append_song(&g_playlist,
|
||||||
|
data->client->player_control,
|
||||||
|
song, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,12 @@
|
|||||||
|
|
||||||
struct client;
|
struct client;
|
||||||
struct locate_item_list;
|
struct locate_item_list;
|
||||||
|
struct player_control;
|
||||||
|
|
||||||
int printAllIn(struct client *client, const char *name);
|
int printAllIn(struct client *client, const char *name);
|
||||||
|
|
||||||
int addAllIn(const char *name);
|
int
|
||||||
|
addAllIn(struct player_control *pc, const char *name);
|
||||||
|
|
||||||
int addAllInToStoredPlaylist(const char *name, const char *utf8file);
|
int addAllInToStoredPlaylist(const char *name, const char *utf8file);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ decoder_initialized(struct decoder *decoder,
|
|||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
|
|
||||||
player_lock_signal();
|
player_lock_signal(dc->player_control);
|
||||||
|
|
||||||
g_debug("audio_format=%s, seekable=%s",
|
g_debug("audio_format=%s, seekable=%s",
|
||||||
audio_format_to_string(&dc->in_audio_format, &af_string),
|
audio_format_to_string(&dc->in_audio_format, &af_string),
|
||||||
@ -117,7 +117,7 @@ decoder_command_finished(struct decoder *decoder)
|
|||||||
dc->command = DECODE_COMMAND_NONE;
|
dc->command = DECODE_COMMAND_NONE;
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
|
|
||||||
player_lock_signal();
|
player_lock_signal(dc->player_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
|
double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
|
||||||
@ -214,7 +214,7 @@ do_send_tag(struct decoder *decoder, struct input_stream *is,
|
|||||||
/* there is a partial chunk - flush it, we want the
|
/* there is a partial chunk - flush it, we want the
|
||||||
tag in a new chunk */
|
tag in a new chunk */
|
||||||
decoder_flush_chunk(decoder);
|
decoder_flush_chunk(decoder);
|
||||||
player_lock_signal();
|
player_lock_signal(decoder->dc->player_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(decoder->chunk == NULL);
|
assert(decoder->chunk == NULL);
|
||||||
@ -329,7 +329,7 @@ decoder_data(struct decoder *decoder,
|
|||||||
if (dest == NULL) {
|
if (dest == NULL) {
|
||||||
/* the chunk is full, flush it */
|
/* the chunk is full, flush it */
|
||||||
decoder_flush_chunk(decoder);
|
decoder_flush_chunk(decoder);
|
||||||
player_lock_signal();
|
player_lock_signal(dc->player_control);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +348,7 @@ decoder_data(struct decoder *decoder,
|
|||||||
if (full) {
|
if (full) {
|
||||||
/* the chunk is full, flush it */
|
/* the chunk is full, flush it */
|
||||||
decoder_flush_chunk(decoder);
|
decoder_flush_chunk(decoder);
|
||||||
player_lock_signal();
|
player_lock_signal(dc->player_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
data += nbytes;
|
data += nbytes;
|
||||||
@ -432,7 +432,7 @@ decoder_replay_gain(struct decoder *decoder,
|
|||||||
replay gain values affect the following
|
replay gain values affect the following
|
||||||
samples */
|
samples */
|
||||||
decoder_flush_chunk(decoder);
|
decoder_flush_chunk(decoder);
|
||||||
player_lock_signal();
|
player_lock_signal(decoder->dc->player_control);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
decoder->replay_gain_serial = 0;
|
decoder->replay_gain_serial = 0;
|
||||||
|
@ -28,8 +28,9 @@
|
|||||||
#define G_LOG_DOMAIN "decoder_control"
|
#define G_LOG_DOMAIN "decoder_control"
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_init(struct decoder_control *dc)
|
dc_init(struct decoder_control *dc, struct player_control *pc)
|
||||||
{
|
{
|
||||||
|
dc->player_control = pc;
|
||||||
dc->thread = NULL;
|
dc->thread = NULL;
|
||||||
|
|
||||||
dc->mutex = g_mutex_new();
|
dc->mutex = g_mutex_new();
|
||||||
@ -62,7 +63,7 @@ static void
|
|||||||
dc_command_wait_locked(struct decoder_control *dc)
|
dc_command_wait_locked(struct decoder_control *dc)
|
||||||
{
|
{
|
||||||
while (dc->command != DECODE_COMMAND_NONE)
|
while (dc->command != DECODE_COMMAND_NONE)
|
||||||
player_wait_decoder(dc);
|
player_wait_decoder(dc->player_control, dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
struct player_control;
|
||||||
|
|
||||||
enum decoder_state {
|
enum decoder_state {
|
||||||
DECODE_STATE_STOP = 0,
|
DECODE_STATE_STOP = 0,
|
||||||
DECODE_STATE_START,
|
DECODE_STATE_START,
|
||||||
@ -42,6 +44,12 @@ enum decoder_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct decoder_control {
|
struct decoder_control {
|
||||||
|
/**
|
||||||
|
* The player thread which calls us. This pointer is used to
|
||||||
|
* signal command completion.
|
||||||
|
*/
|
||||||
|
struct player_control *player_control;
|
||||||
|
|
||||||
/** the handle of the decoder thread, or NULL if the decoder
|
/** the handle of the decoder thread, or NULL if the decoder
|
||||||
thread isn't running */
|
thread isn't running */
|
||||||
GThread *thread;
|
GThread *thread;
|
||||||
@ -98,7 +106,7 @@ struct decoder_control {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_init(struct decoder_control *dc);
|
dc_init(struct decoder_control *dc, struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_deinit(struct decoder_control *dc);
|
dc_deinit(struct decoder_control *dc);
|
||||||
|
@ -65,7 +65,7 @@ need_chunks(struct decoder_control *dc, struct input_stream *is, bool do_wait)
|
|||||||
|
|
||||||
if ((is == NULL || !decoder_input_buffer(dc, is)) && do_wait) {
|
if ((is == NULL || !decoder_input_buffer(dc, is)) && do_wait) {
|
||||||
decoder_wait(dc);
|
decoder_wait(dc);
|
||||||
player_signal();
|
player_signal(dc->player_control);
|
||||||
|
|
||||||
return dc->command;
|
return dc->command;
|
||||||
}
|
}
|
||||||
|
@ -383,7 +383,7 @@ decoder_run_song(struct decoder_control *dc,
|
|||||||
dc->state = DECODE_STATE_START;
|
dc->state = DECODE_STATE_START;
|
||||||
dc->command = DECODE_COMMAND_NONE;
|
dc->command = DECODE_COMMAND_NONE;
|
||||||
|
|
||||||
player_signal();
|
player_signal(dc->player_control);
|
||||||
|
|
||||||
pcm_convert_init(&decoder.conv_state);
|
pcm_convert_init(&decoder.conv_state);
|
||||||
|
|
||||||
@ -464,13 +464,13 @@ decoder_task(gpointer arg)
|
|||||||
|
|
||||||
dc->command = DECODE_COMMAND_NONE;
|
dc->command = DECODE_COMMAND_NONE;
|
||||||
|
|
||||||
player_signal();
|
player_signal(dc->player_control);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DECODE_COMMAND_STOP:
|
case DECODE_COMMAND_STOP:
|
||||||
dc->command = DECODE_COMMAND_NONE;
|
dc->command = DECODE_COMMAND_NONE;
|
||||||
|
|
||||||
player_signal();
|
player_signal(dc->player_control);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DECODE_COMMAND_NONE:
|
case DECODE_COMMAND_NONE:
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "glib_compat.h"
|
#include "glib_compat.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -39,7 +40,7 @@ static void
|
|||||||
listen_callback(int fd, const struct sockaddr *address,
|
listen_callback(int fd, const struct sockaddr *address,
|
||||||
size_t address_length, int uid, G_GNUC_UNUSED void *ctx)
|
size_t address_length, int uid, G_GNUC_UNUSED void *ctx)
|
||||||
{
|
{
|
||||||
client_new(fd, address, address_length, uid);
|
client_new(global_player_control, fd, address, address_length, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
19
src/main.c
19
src/main.c
@ -94,6 +94,8 @@ GMainLoop *main_loop;
|
|||||||
|
|
||||||
GCond *main_cond;
|
GCond *main_cond;
|
||||||
|
|
||||||
|
struct player_control *global_player_control;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue_daemonize_init(const struct options *options)
|
glue_daemonize_init(const struct options *options)
|
||||||
{
|
{
|
||||||
@ -183,7 +185,8 @@ glue_sticker_init(void)
|
|||||||
static void
|
static void
|
||||||
glue_state_file_init(void)
|
glue_state_file_init(void)
|
||||||
{
|
{
|
||||||
state_file_init(config_get_path(CONF_STATE_FILE));
|
state_file_init(config_get_path(CONF_STATE_FILE),
|
||||||
|
global_player_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -254,7 +257,7 @@ initialize_decoder_and_player(void)
|
|||||||
if (buffered_before_play > buffered_chunks)
|
if (buffered_before_play > buffered_chunks)
|
||||||
buffered_before_play = buffered_chunks;
|
buffered_before_play = buffered_chunks;
|
||||||
|
|
||||||
pc_init(buffered_chunks, buffered_before_play);
|
global_player_control = pc_new(buffered_chunks, buffered_before_play);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -364,7 +367,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
initialize_decoder_and_player();
|
initialize_decoder_and_player();
|
||||||
volume_init();
|
volume_init();
|
||||||
initAudioConfig();
|
initAudioConfig();
|
||||||
audio_output_all_init();
|
audio_output_all_init(global_player_control);
|
||||||
client_manager_init();
|
client_manager_init();
|
||||||
replay_gain_global_init();
|
replay_gain_global_init();
|
||||||
|
|
||||||
@ -384,7 +387,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
|
|
||||||
initZeroconf();
|
initZeroconf();
|
||||||
|
|
||||||
player_create();
|
player_create(global_player_control);
|
||||||
|
|
||||||
if (create_db) {
|
if (create_db) {
|
||||||
/* the database failed to load: recreate the
|
/* the database failed to load: recreate the
|
||||||
@ -410,7 +413,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* enable all audio outputs (if not already done by
|
/* enable all audio outputs (if not already done by
|
||||||
playlist_state_restore() */
|
playlist_state_restore() */
|
||||||
pc_update_audio();
|
pc_update_audio(global_player_control);
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
win32_app_started();
|
win32_app_started();
|
||||||
@ -431,8 +434,8 @@ int mpd_main(int argc, char *argv[])
|
|||||||
mpd_inotify_finish();
|
mpd_inotify_finish();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
state_file_finish();
|
state_file_finish(global_player_control);
|
||||||
pc_kill();
|
pc_kill(global_player_control);
|
||||||
finishZeroconf();
|
finishZeroconf();
|
||||||
client_manager_deinit();
|
client_manager_deinit();
|
||||||
listen_global_finish();
|
listen_global_finish();
|
||||||
@ -457,7 +460,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
mapper_finish();
|
mapper_finish();
|
||||||
path_global_finish();
|
path_global_finish();
|
||||||
finishPermissions();
|
finishPermissions();
|
||||||
pc_deinit();
|
pc_free(global_player_control);
|
||||||
command_finish();
|
command_finish();
|
||||||
update_global_finish();
|
update_global_finish();
|
||||||
decoder_plugin_deinit_all();
|
decoder_plugin_deinit_all();
|
||||||
|
@ -28,6 +28,8 @@ extern GMainLoop *main_loop;
|
|||||||
|
|
||||||
extern GCond *main_cond;
|
extern GCond *main_cond;
|
||||||
|
|
||||||
|
extern struct player_control *global_player_control;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A entry point for application.
|
* A entry point for application.
|
||||||
* On non-Windows platforms this is called directly from main()
|
* On non-Windows platforms this is called directly from main()
|
||||||
|
@ -100,7 +100,7 @@ audio_output_config_count(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_all_init(void)
|
audio_output_all_init(struct player_control *pc)
|
||||||
{
|
{
|
||||||
const struct config_param *param = NULL;
|
const struct config_param *param = NULL;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@ -121,7 +121,7 @@ audio_output_all_init(void)
|
|||||||
/* only allow param to be NULL if there just one audioOutput */
|
/* only allow param to be NULL if there just one audioOutput */
|
||||||
assert(param || (num_audio_outputs == 1));
|
assert(param || (num_audio_outputs == 1));
|
||||||
|
|
||||||
if (!audio_output_init(output, param, &error)) {
|
if (!audio_output_init(output, param, pc, &error)) {
|
||||||
if (param != NULL)
|
if (param != NULL)
|
||||||
MPD_ERROR("line %i: %s",
|
MPD_ERROR("line %i: %s",
|
||||||
param->line, error->message);
|
param->line, error->message);
|
||||||
@ -473,17 +473,17 @@ audio_output_all_check(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_output_all_wait(unsigned threshold)
|
audio_output_all_wait(struct player_control *pc, unsigned threshold)
|
||||||
{
|
{
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
if (audio_output_all_check() < threshold) {
|
if (audio_output_all_check() < threshold) {
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
player_wait();
|
player_wait(pc);
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
return audio_output_all_check() < threshold;
|
return audio_output_all_check() < threshold;
|
||||||
}
|
}
|
||||||
|
@ -32,13 +32,14 @@
|
|||||||
struct audio_format;
|
struct audio_format;
|
||||||
struct music_buffer;
|
struct music_buffer;
|
||||||
struct music_chunk;
|
struct music_chunk;
|
||||||
|
struct player_control;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global initialization: load audio outputs from the configuration
|
* Global initialization: load audio outputs from the configuration
|
||||||
* file and initialize them.
|
* file and initialize them.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
audio_output_all_init(void);
|
audio_output_all_init(struct player_control *pc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global finalization: free memory occupied by audio outputs. All
|
* Global finalization: free memory occupied by audio outputs. All
|
||||||
@ -127,7 +128,7 @@ audio_output_all_check(void);
|
|||||||
* @return true if there are less than #threshold chunks in the pipe
|
* @return true if there are less than #threshold chunks in the pipe
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
audio_output_all_wait(unsigned threshold);
|
audio_output_all_wait(struct player_control *pc, unsigned threshold);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts all audio outputs into pause mode. Most implementations will
|
* Puts all audio outputs into pause mode. Most implementations will
|
||||||
|
@ -50,7 +50,7 @@ audio_output_enable_index(unsigned idx)
|
|||||||
ao->enabled = true;
|
ao->enabled = true;
|
||||||
idle_add(IDLE_OUTPUT);
|
idle_add(IDLE_OUTPUT);
|
||||||
|
|
||||||
pc_update_audio();
|
pc_update_audio(ao->player_control);
|
||||||
|
|
||||||
++audio_output_state_version;
|
++audio_output_state_version;
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ audio_output_disable_index(unsigned idx)
|
|||||||
idle_add(IDLE_MIXER);
|
idle_add(IDLE_MIXER);
|
||||||
}
|
}
|
||||||
|
|
||||||
pc_update_audio();
|
pc_update_audio(ao->player_control);
|
||||||
|
|
||||||
++audio_output_state_version;
|
++audio_output_state_version;
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ struct audio_output;
|
|||||||
struct audio_format;
|
struct audio_format;
|
||||||
struct config_param;
|
struct config_param;
|
||||||
struct music_pipe;
|
struct music_pipe;
|
||||||
|
struct player_control;
|
||||||
|
|
||||||
static inline GQuark
|
static inline GQuark
|
||||||
audio_output_quark(void)
|
audio_output_quark(void)
|
||||||
@ -38,6 +39,7 @@ audio_output_quark(void)
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
audio_output_init(struct audio_output *ao, const struct config_param *param,
|
audio_output_init(struct audio_output *ao, const struct config_param *param,
|
||||||
|
struct player_control *pc,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,8 +127,12 @@ audio_output_load_mixer(void *ao, const struct config_param *param,
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
audio_output_init(struct audio_output *ao, const struct config_param *param,
|
audio_output_init(struct audio_output *ao, const struct config_param *param,
|
||||||
|
struct player_control *pc,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
|
assert(ao != NULL);
|
||||||
|
assert(pc != NULL);
|
||||||
|
|
||||||
const struct audio_output_plugin *plugin = NULL;
|
const struct audio_output_plugin *plugin = NULL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
@ -249,6 +253,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
|
|||||||
ao->command = AO_COMMAND_NONE;
|
ao->command = AO_COMMAND_NONE;
|
||||||
ao->mutex = g_mutex_new();
|
ao->mutex = g_mutex_new();
|
||||||
ao->cond = g_cond_new();
|
ao->cond = g_cond_new();
|
||||||
|
ao->player_control = pc;
|
||||||
|
|
||||||
ao->data = ao_plugin_init(plugin,
|
ao->data = ao_plugin_init(plugin,
|
||||||
&ao->config_audio_format,
|
&ao->config_audio_format,
|
||||||
|
@ -207,6 +207,12 @@ struct audio_output {
|
|||||||
*/
|
*/
|
||||||
GCond *cond;
|
GCond *cond;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The player_control object which "owns" this output. This
|
||||||
|
* object is needed to signal command completion.
|
||||||
|
*/
|
||||||
|
struct player_control *player_control;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The #music_chunk which is currently being played. All
|
* The #music_chunk which is currently being played. All
|
||||||
* chunks before this one may be returned to the
|
* chunks before this one may be returned to the
|
||||||
|
@ -530,7 +530,7 @@ ao_play(struct audio_output *ao)
|
|||||||
ao->chunk_finished = true;
|
ao->chunk_finished = true;
|
||||||
|
|
||||||
g_mutex_unlock(ao->mutex);
|
g_mutex_unlock(ao->mutex);
|
||||||
player_lock_signal();
|
player_lock_signal(ao->player_control);
|
||||||
g_mutex_lock(ao->mutex);
|
g_mutex_lock(ao->mutex);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -32,237 +32,247 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
struct player_control pc;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pc_enqueue_song_locked(struct song *song);
|
pc_enqueue_song_locked(struct player_control *pc, struct song *song);
|
||||||
|
|
||||||
void pc_init(unsigned buffer_chunks, unsigned int buffered_before_play)
|
struct player_control *
|
||||||
|
pc_new(unsigned buffer_chunks, unsigned int buffered_before_play)
|
||||||
{
|
{
|
||||||
pc.buffer_chunks = buffer_chunks;
|
struct player_control *pc = g_new0(struct player_control, 1);
|
||||||
pc.buffered_before_play = buffered_before_play;
|
|
||||||
|
|
||||||
pc.mutex = g_mutex_new();
|
pc->buffer_chunks = buffer_chunks;
|
||||||
pc.cond = g_cond_new();
|
pc->buffered_before_play = buffered_before_play;
|
||||||
|
|
||||||
pc.command = PLAYER_COMMAND_NONE;
|
pc->mutex = g_mutex_new();
|
||||||
pc.error = PLAYER_ERROR_NOERROR;
|
pc->cond = g_cond_new();
|
||||||
pc.state = PLAYER_STATE_STOP;
|
|
||||||
pc.cross_fade_seconds = 0;
|
|
||||||
pc.mixramp_db = 0;
|
|
||||||
pc.mixramp_delay_seconds = nanf("");
|
|
||||||
}
|
|
||||||
|
|
||||||
void pc_deinit(void)
|
pc->command = PLAYER_COMMAND_NONE;
|
||||||
{
|
pc->error = PLAYER_ERROR_NOERROR;
|
||||||
g_cond_free(pc.cond);
|
pc->state = PLAYER_STATE_STOP;
|
||||||
g_mutex_free(pc.mutex);
|
pc->cross_fade_seconds = 0;
|
||||||
|
pc->mixramp_db = 0;
|
||||||
|
pc->mixramp_delay_seconds = nanf("");
|
||||||
|
|
||||||
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
player_wait_decoder(struct decoder_control *dc)
|
pc_free(struct player_control *pc)
|
||||||
{
|
{
|
||||||
|
g_cond_free(pc->cond);
|
||||||
|
g_mutex_free(pc->mutex);
|
||||||
|
g_free(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
player_wait_decoder(struct player_control *pc, struct decoder_control *dc)
|
||||||
|
{
|
||||||
|
assert(pc != NULL);
|
||||||
|
assert(dc != NULL);
|
||||||
|
assert(dc->player_control == pc);
|
||||||
|
|
||||||
/* during this function, the decoder lock is held, because
|
/* during this function, the decoder lock is held, because
|
||||||
we're waiting for the decoder thread */
|
we're waiting for the decoder thread */
|
||||||
g_cond_wait(pc.cond, dc->mutex);
|
g_cond_wait(pc->cond, dc->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_song_deleted(const struct song *song)
|
pc_song_deleted(struct player_control *pc, const struct song *song)
|
||||||
{
|
{
|
||||||
if (pc.errored_song == song) {
|
if (pc->errored_song == song) {
|
||||||
pc.error = PLAYER_ERROR_NOERROR;
|
pc->error = PLAYER_ERROR_NOERROR;
|
||||||
pc.errored_song = NULL;
|
pc->errored_song = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
player_command_wait_locked(void)
|
player_command_wait_locked(struct player_control *pc)
|
||||||
{
|
{
|
||||||
while (pc.command != PLAYER_COMMAND_NONE)
|
while (pc->command != PLAYER_COMMAND_NONE)
|
||||||
g_cond_wait(main_cond, pc.mutex);
|
g_cond_wait(main_cond, pc->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
player_command_locked(enum player_command cmd)
|
player_command_locked(struct player_control *pc, enum player_command cmd)
|
||||||
{
|
{
|
||||||
assert(pc.command == PLAYER_COMMAND_NONE);
|
assert(pc->command == PLAYER_COMMAND_NONE);
|
||||||
|
|
||||||
pc.command = cmd;
|
pc->command = cmd;
|
||||||
player_signal();
|
player_signal(pc);
|
||||||
player_command_wait_locked();
|
player_command_wait_locked(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
player_command(enum player_command cmd)
|
player_command(struct player_control *pc, enum player_command cmd)
|
||||||
{
|
{
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
player_command_locked(cmd);
|
player_command_locked(pc, cmd);
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_play(struct song *song)
|
pc_play(struct player_control *pc, struct song *song)
|
||||||
{
|
{
|
||||||
assert(song != NULL);
|
assert(song != NULL);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
if (pc.state != PLAYER_STATE_STOP)
|
if (pc->state != PLAYER_STATE_STOP)
|
||||||
player_command_locked(PLAYER_COMMAND_STOP);
|
player_command_locked(pc, PLAYER_COMMAND_STOP);
|
||||||
|
|
||||||
assert(pc.next_song == NULL);
|
assert(pc->next_song == NULL);
|
||||||
|
|
||||||
pc_enqueue_song_locked(song);
|
pc_enqueue_song_locked(pc, song);
|
||||||
|
|
||||||
assert(pc.next_song == NULL);
|
assert(pc->next_song == NULL);
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
idle_add(IDLE_PLAYER);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pc_cancel(void)
|
|
||||||
{
|
|
||||||
player_command(PLAYER_COMMAND_CANCEL);
|
|
||||||
assert(pc.next_song == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pc_stop(void)
|
|
||||||
{
|
|
||||||
player_command(PLAYER_COMMAND_CLOSE_AUDIO);
|
|
||||||
assert(pc.next_song == NULL);
|
|
||||||
|
|
||||||
idle_add(IDLE_PLAYER);
|
idle_add(IDLE_PLAYER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_update_audio(void)
|
pc_cancel(struct player_control *pc)
|
||||||
{
|
{
|
||||||
player_command(PLAYER_COMMAND_UPDATE_AUDIO);
|
player_command(pc, PLAYER_COMMAND_CANCEL);
|
||||||
|
assert(pc->next_song == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_kill(void)
|
pc_stop(struct player_control *pc)
|
||||||
{
|
{
|
||||||
assert(pc.thread != NULL);
|
player_command(pc, PLAYER_COMMAND_CLOSE_AUDIO);
|
||||||
|
assert(pc->next_song == NULL);
|
||||||
player_command(PLAYER_COMMAND_EXIT);
|
|
||||||
g_thread_join(pc.thread);
|
|
||||||
pc.thread = NULL;
|
|
||||||
|
|
||||||
idle_add(IDLE_PLAYER);
|
idle_add(IDLE_PLAYER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_pause(void)
|
pc_update_audio(struct player_control *pc)
|
||||||
{
|
{
|
||||||
player_lock();
|
player_command(pc, PLAYER_COMMAND_UPDATE_AUDIO);
|
||||||
|
}
|
||||||
|
|
||||||
if (pc.state != PLAYER_STATE_STOP) {
|
void
|
||||||
player_command_locked(PLAYER_COMMAND_PAUSE);
|
pc_kill(struct player_control *pc)
|
||||||
|
{
|
||||||
|
assert(pc->thread != NULL);
|
||||||
|
|
||||||
|
player_command(pc, PLAYER_COMMAND_EXIT);
|
||||||
|
g_thread_join(pc->thread);
|
||||||
|
pc->thread = NULL;
|
||||||
|
|
||||||
|
idle_add(IDLE_PLAYER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pc_pause(struct player_control *pc)
|
||||||
|
{
|
||||||
|
player_lock(pc);
|
||||||
|
|
||||||
|
if (pc->state != PLAYER_STATE_STOP) {
|
||||||
|
player_command_locked(pc, PLAYER_COMMAND_PAUSE);
|
||||||
idle_add(IDLE_PLAYER);
|
idle_add(IDLE_PLAYER);
|
||||||
}
|
}
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pc_pause_locked(void)
|
pc_pause_locked(struct player_control *pc)
|
||||||
{
|
{
|
||||||
if (pc.state != PLAYER_STATE_STOP) {
|
if (pc->state != PLAYER_STATE_STOP) {
|
||||||
player_command_locked(PLAYER_COMMAND_PAUSE);
|
player_command_locked(pc, PLAYER_COMMAND_PAUSE);
|
||||||
idle_add(IDLE_PLAYER);
|
idle_add(IDLE_PLAYER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_set_pause(bool pause_flag)
|
pc_set_pause(struct player_control *pc, bool pause_flag)
|
||||||
{
|
{
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
switch (pc.state) {
|
switch (pc->state) {
|
||||||
case PLAYER_STATE_STOP:
|
case PLAYER_STATE_STOP:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_STATE_PLAY:
|
case PLAYER_STATE_PLAY:
|
||||||
if (pause_flag)
|
if (pause_flag)
|
||||||
pc_pause_locked();
|
pc_pause_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_STATE_PAUSE:
|
case PLAYER_STATE_PAUSE:
|
||||||
if (!pause_flag)
|
if (!pause_flag)
|
||||||
pc_pause_locked();
|
pc_pause_locked(pc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_get_status(struct player_status *status)
|
pc_get_status(struct player_control *pc, struct player_status *status)
|
||||||
{
|
{
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
player_command_locked(PLAYER_COMMAND_REFRESH);
|
player_command_locked(pc, PLAYER_COMMAND_REFRESH);
|
||||||
|
|
||||||
status->state = pc.state;
|
status->state = pc->state;
|
||||||
|
|
||||||
if (pc.state != PLAYER_STATE_STOP) {
|
if (pc->state != PLAYER_STATE_STOP) {
|
||||||
status->bit_rate = pc.bit_rate;
|
status->bit_rate = pc->bit_rate;
|
||||||
status->audio_format = pc.audio_format;
|
status->audio_format = pc->audio_format;
|
||||||
status->total_time = pc.total_time;
|
status->total_time = pc->total_time;
|
||||||
status->elapsed_time = pc.elapsed_time;
|
status->elapsed_time = pc->elapsed_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum player_state
|
enum player_state
|
||||||
pc_get_state(void)
|
pc_get_state(struct player_control *pc)
|
||||||
{
|
{
|
||||||
return pc.state;
|
return pc->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_clear_error(void)
|
pc_clear_error(struct player_control *pc)
|
||||||
{
|
{
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
pc.error = PLAYER_ERROR_NOERROR;
|
pc->error = PLAYER_ERROR_NOERROR;
|
||||||
pc.errored_song = NULL;
|
pc->errored_song = NULL;
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum player_error
|
enum player_error
|
||||||
pc_get_error(void)
|
pc_get_error(struct player_control *pc)
|
||||||
{
|
{
|
||||||
return pc.error;
|
return pc->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
pc_errored_song_uri(void)
|
pc_errored_song_uri(struct player_control *pc)
|
||||||
{
|
{
|
||||||
return song_get_uri(pc.errored_song);
|
return song_get_uri(pc->errored_song);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
pc_get_error_message(void)
|
pc_get_error_message(struct player_control *pc)
|
||||||
{
|
{
|
||||||
char *error;
|
char *error;
|
||||||
char *uri;
|
char *uri;
|
||||||
|
|
||||||
switch (pc.error) {
|
switch (pc->error) {
|
||||||
case PLAYER_ERROR_NOERROR:
|
case PLAYER_ERROR_NOERROR:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
case PLAYER_ERROR_FILENOTFOUND:
|
case PLAYER_ERROR_FILENOTFOUND:
|
||||||
uri = pc_errored_song_uri();
|
uri = pc_errored_song_uri(pc);
|
||||||
error = g_strdup_printf("file \"%s\" does not exist or is inaccessible", uri);
|
error = g_strdup_printf("file \"%s\" does not exist or is inaccessible", uri);
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
case PLAYER_ERROR_FILE:
|
case PLAYER_ERROR_FILE:
|
||||||
uri = pc_errored_song_uri();
|
uri = pc_errored_song_uri(pc);
|
||||||
error = g_strdup_printf("problems decoding \"%s\"", uri);
|
error = g_strdup_printf("problems decoding \"%s\"", uri);
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
return error;
|
return error;
|
||||||
@ -274,7 +284,7 @@ pc_get_error_message(void)
|
|||||||
return g_strdup("system error occured");
|
return g_strdup("system error occured");
|
||||||
|
|
||||||
case PLAYER_ERROR_UNKTYPE:
|
case PLAYER_ERROR_UNKTYPE:
|
||||||
uri = pc_errored_song_uri();
|
uri = pc_errored_song_uri(pc);
|
||||||
error = g_strdup_printf("file type of \"%s\" is unknown", uri);
|
error = g_strdup_printf("file type of \"%s\" is unknown", uri);
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
return error;
|
return error;
|
||||||
@ -285,40 +295,40 @@ pc_get_error_message(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pc_enqueue_song_locked(struct song *song)
|
pc_enqueue_song_locked(struct player_control *pc, struct song *song)
|
||||||
{
|
{
|
||||||
assert(song != NULL);
|
assert(song != NULL);
|
||||||
assert(pc.next_song == NULL);
|
assert(pc->next_song == NULL);
|
||||||
|
|
||||||
pc.next_song = song;
|
pc->next_song = song;
|
||||||
player_command_locked(PLAYER_COMMAND_QUEUE);
|
player_command_locked(pc, PLAYER_COMMAND_QUEUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_enqueue_song(struct song *song)
|
pc_enqueue_song(struct player_control *pc, struct song *song)
|
||||||
{
|
{
|
||||||
assert(song != NULL);
|
assert(song != NULL);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
pc_enqueue_song_locked(song);
|
pc_enqueue_song_locked(pc, song);
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pc_seek(struct song *song, float seek_time)
|
pc_seek(struct player_control *pc, struct song *song, float seek_time)
|
||||||
{
|
{
|
||||||
assert(song != NULL);
|
assert(song != NULL);
|
||||||
|
|
||||||
if (pc.state == PLAYER_STATE_STOP)
|
if (pc->state == PLAYER_STATE_STOP)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
pc.next_song = song;
|
pc->next_song = song;
|
||||||
pc.seek_where = seek_time;
|
pc->seek_where = seek_time;
|
||||||
player_command_locked(PLAYER_COMMAND_SEEK);
|
player_command_locked(pc, PLAYER_COMMAND_SEEK);
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
assert(pc.next_song == NULL);
|
assert(pc->next_song == NULL);
|
||||||
|
|
||||||
idle_add(IDLE_PLAYER);
|
idle_add(IDLE_PLAYER);
|
||||||
|
|
||||||
@ -326,51 +336,51 @@ pc_seek(struct song *song, float seek_time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
pc_get_cross_fade(void)
|
pc_get_cross_fade(const struct player_control *pc)
|
||||||
{
|
{
|
||||||
return pc.cross_fade_seconds;
|
return pc->cross_fade_seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_set_cross_fade(float cross_fade_seconds)
|
pc_set_cross_fade(struct player_control *pc, float cross_fade_seconds)
|
||||||
{
|
{
|
||||||
if (cross_fade_seconds < 0)
|
if (cross_fade_seconds < 0)
|
||||||
cross_fade_seconds = 0;
|
cross_fade_seconds = 0;
|
||||||
pc.cross_fade_seconds = cross_fade_seconds;
|
pc->cross_fade_seconds = cross_fade_seconds;
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
pc_get_mixramp_db(void)
|
pc_get_mixramp_db(const struct player_control *pc)
|
||||||
{
|
{
|
||||||
return pc.mixramp_db;
|
return pc->mixramp_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_set_mixramp_db(float mixramp_db)
|
pc_set_mixramp_db(struct player_control *pc, float mixramp_db)
|
||||||
{
|
{
|
||||||
pc.mixramp_db = mixramp_db;
|
pc->mixramp_db = mixramp_db;
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
pc_get_mixramp_delay(void)
|
pc_get_mixramp_delay(const struct player_control *pc)
|
||||||
{
|
{
|
||||||
return pc.mixramp_delay_seconds;
|
return pc->mixramp_delay_seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_set_mixramp_delay(float mixramp_delay_seconds)
|
pc_set_mixramp_delay(struct player_control *pc, float mixramp_delay_seconds)
|
||||||
{
|
{
|
||||||
pc.mixramp_delay_seconds = mixramp_delay_seconds;
|
pc->mixramp_delay_seconds = mixramp_delay_seconds;
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
pc_get_total_play_time(void)
|
pc_get_total_play_time(const struct player_control *pc)
|
||||||
{
|
{
|
||||||
return pc.total_play_time;
|
return pc->total_play_time;
|
||||||
}
|
}
|
||||||
|
@ -116,28 +116,28 @@ struct player_control {
|
|||||||
double total_play_time;
|
double total_play_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct player_control pc;
|
struct player_control *
|
||||||
|
pc_new(unsigned buffer_chunks, unsigned buffered_before_play);
|
||||||
|
|
||||||
void pc_init(unsigned buffer_chunks, unsigned buffered_before_play);
|
void
|
||||||
|
pc_free(struct player_control *pc);
|
||||||
void pc_deinit(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks the #player_control object.
|
* Locks the #player_control object.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
player_lock(void)
|
player_lock(struct player_control *pc)
|
||||||
{
|
{
|
||||||
g_mutex_lock(pc.mutex);
|
g_mutex_lock(pc->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlocks the #player_control object.
|
* Unlocks the #player_control object.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
player_unlock(void)
|
player_unlock(struct player_control *pc)
|
||||||
{
|
{
|
||||||
g_mutex_unlock(pc.mutex);
|
g_mutex_unlock(pc->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,9 +146,9 @@ player_unlock(void)
|
|||||||
* to calling this function.
|
* to calling this function.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
player_wait(void)
|
player_wait(struct player_control *pc)
|
||||||
{
|
{
|
||||||
g_cond_wait(pc.cond, pc.mutex);
|
g_cond_wait(pc->cond, pc->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,16 +159,16 @@ player_wait(void)
|
|||||||
* Note the small difference to the player_wait() function!
|
* Note the small difference to the player_wait() function!
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
player_wait_decoder(struct decoder_control *dc);
|
player_wait_decoder(struct player_control *pc, struct decoder_control *dc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals the #player_control object. The object should be locked
|
* Signals the #player_control object. The object should be locked
|
||||||
* prior to calling this function.
|
* prior to calling this function.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
player_signal(void)
|
player_signal(struct player_control *pc)
|
||||||
{
|
{
|
||||||
g_cond_signal(pc.cond);
|
g_cond_signal(pc->cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,11 +176,11 @@ player_signal(void)
|
|||||||
* locked by this function.
|
* locked by this function.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
player_lock_signal(void)
|
player_lock_signal(struct player_control *pc)
|
||||||
{
|
{
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
player_signal();
|
player_signal(pc);
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,33 +189,34 @@ player_lock_signal(void)
|
|||||||
* not point to an invalid pointer.
|
* not point to an invalid pointer.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
pc_song_deleted(const struct song *song);
|
pc_song_deleted(struct player_control *pc, const struct song *song);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_play(struct song *song);
|
pc_play(struct player_control *pc, struct song *song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* see PLAYER_COMMAND_CANCEL
|
* see PLAYER_COMMAND_CANCEL
|
||||||
*/
|
*/
|
||||||
void pc_cancel(void);
|
void
|
||||||
|
pc_cancel(struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_set_pause(bool pause_flag);
|
pc_set_pause(struct player_control *pc, bool pause_flag);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_pause(void);
|
pc_pause(struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_kill(void);
|
pc_kill(struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_get_status(struct player_status *status);
|
pc_get_status(struct player_control *pc, struct player_status *status);
|
||||||
|
|
||||||
enum player_state
|
enum player_state
|
||||||
pc_get_state(void);
|
pc_get_state(struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_clear_error(void);
|
pc_clear_error(struct player_control *pc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the human-readable message describing the last error during
|
* Returns the human-readable message describing the last error during
|
||||||
@ -223,19 +224,19 @@ pc_clear_error(void);
|
|||||||
* returned string.
|
* returned string.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
pc_get_error_message(void);
|
pc_get_error_message(struct player_control *pc);
|
||||||
|
|
||||||
enum player_error
|
enum player_error
|
||||||
pc_get_error(void);
|
pc_get_error(struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_stop(void);
|
pc_stop(struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_update_audio(void);
|
pc_update_audio(struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_enqueue_song(struct song *song);
|
pc_enqueue_song(struct player_control *pc, struct song *song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the player thread seek the specified song to a position.
|
* Makes the player thread seek the specified song to a position.
|
||||||
@ -244,27 +245,27 @@ pc_enqueue_song(struct song *song);
|
|||||||
* playing currently)
|
* playing currently)
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
pc_seek(struct song *song, float seek_time);
|
pc_seek(struct player_control *pc, struct song *song, float seek_time);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_set_cross_fade(float cross_fade_seconds);
|
pc_set_cross_fade(struct player_control *pc, float cross_fade_seconds);
|
||||||
|
|
||||||
float
|
float
|
||||||
pc_get_cross_fade(void);
|
pc_get_cross_fade(const struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_set_mixramp_db(float mixramp_db);
|
pc_set_mixramp_db(struct player_control *pc, float mixramp_db);
|
||||||
|
|
||||||
float
|
float
|
||||||
pc_get_mixramp_db(void);
|
pc_get_mixramp_db(const struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_set_mixramp_delay(float mixramp_delay_seconds);
|
pc_set_mixramp_delay(struct player_control *pc, float mixramp_delay_seconds);
|
||||||
|
|
||||||
float
|
float
|
||||||
pc_get_mixramp_delay(void);
|
pc_get_mixramp_delay(const struct player_control *pc);
|
||||||
|
|
||||||
double
|
double
|
||||||
pc_get_total_play_time(void);
|
pc_get_total_play_time(const struct player_control *pc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -48,6 +48,8 @@ enum xfade_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct player {
|
struct player {
|
||||||
|
struct player_control *pc;
|
||||||
|
|
||||||
struct decoder_control *dc;
|
struct decoder_control *dc;
|
||||||
|
|
||||||
struct music_pipe *pipe;
|
struct music_pipe *pipe;
|
||||||
@ -117,19 +119,21 @@ struct player {
|
|||||||
|
|
||||||
static struct music_buffer *player_buffer;
|
static struct music_buffer *player_buffer;
|
||||||
|
|
||||||
static void player_command_finished_locked(void)
|
static void
|
||||||
|
player_command_finished_locked(struct player_control *pc)
|
||||||
{
|
{
|
||||||
assert(pc.command != PLAYER_COMMAND_NONE);
|
assert(pc->command != PLAYER_COMMAND_NONE);
|
||||||
|
|
||||||
pc.command = PLAYER_COMMAND_NONE;
|
pc->command = PLAYER_COMMAND_NONE;
|
||||||
g_cond_signal(main_cond);
|
g_cond_signal(main_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void player_command_finished(void)
|
static void
|
||||||
|
player_command_finished(struct player_control *pc)
|
||||||
{
|
{
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -140,12 +144,13 @@ static void player_command_finished(void)
|
|||||||
static void
|
static void
|
||||||
player_dc_start(struct player *player, struct music_pipe *pipe)
|
player_dc_start(struct player *player, struct music_pipe *pipe)
|
||||||
{
|
{
|
||||||
|
struct player_control *pc = player->pc;
|
||||||
struct decoder_control *dc = player->dc;
|
struct decoder_control *dc = player->dc;
|
||||||
|
|
||||||
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);
|
dc_start(dc, pc->next_song, player_buffer, pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,41 +213,42 @@ player_dc_stop(struct player *player)
|
|||||||
static bool
|
static bool
|
||||||
player_wait_for_decoder(struct player *player)
|
player_wait_for_decoder(struct player *player)
|
||||||
{
|
{
|
||||||
|
struct player_control *pc = player->pc;
|
||||||
struct decoder_control *dc = player->dc;
|
struct decoder_control *dc = player->dc;
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
player->queued = false;
|
player->queued = false;
|
||||||
|
|
||||||
if (decoder_lock_has_failed(dc)) {
|
if (decoder_lock_has_failed(dc)) {
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
pc.errored_song = dc->song;
|
pc->errored_song = dc->song;
|
||||||
pc.error = PLAYER_ERROR_FILE;
|
pc->error = PLAYER_ERROR_FILE;
|
||||||
pc.next_song = NULL;
|
pc->next_song = NULL;
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
player->song = pc.next_song;
|
player->song = pc->next_song;
|
||||||
player->elapsed_time = 0.0;
|
player->elapsed_time = 0.0;
|
||||||
|
|
||||||
/* set the "starting" flag, which will be cleared by
|
/* set the "starting" flag, which will be cleared by
|
||||||
player_check_decoder_startup() */
|
player_check_decoder_startup() */
|
||||||
player->decoder_starting = true;
|
player->decoder_starting = true;
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
/* update player_control's song information */
|
/* update player_control's song information */
|
||||||
pc.total_time = song_get_duration(pc.next_song);
|
pc->total_time = song_get_duration(pc->next_song);
|
||||||
pc.bit_rate = 0;
|
pc->bit_rate = 0;
|
||||||
audio_format_clear(&pc.audio_format);
|
audio_format_clear(&pc->audio_format);
|
||||||
|
|
||||||
/* clear the queued song */
|
/* clear the queued song */
|
||||||
pc.next_song = NULL;
|
pc->next_song = NULL;
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
/* call syncPlaylistWithQueue() in the main thread */
|
/* call syncPlaylistWithQueue() in the main thread */
|
||||||
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
||||||
@ -280,6 +286,7 @@ real_song_duration(const struct song *song, double decoder_duration)
|
|||||||
static bool
|
static bool
|
||||||
player_check_decoder_startup(struct player *player)
|
player_check_decoder_startup(struct player *player)
|
||||||
{
|
{
|
||||||
|
struct player_control *pc = player->pc;
|
||||||
struct decoder_control *dc = player->dc;
|
struct decoder_control *dc = player->dc;
|
||||||
|
|
||||||
assert(player->decoder_starting);
|
assert(player->decoder_starting);
|
||||||
@ -290,10 +297,10 @@ player_check_decoder_startup(struct player *player)
|
|||||||
/* the decoder failed */
|
/* the decoder failed */
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
pc.errored_song = dc->song;
|
pc->errored_song = dc->song;
|
||||||
pc.error = PLAYER_ERROR_FILE;
|
pc->error = PLAYER_ERROR_FILE;
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else if (!decoder_is_starting(dc)) {
|
} else if (!decoder_is_starting(dc)) {
|
||||||
@ -302,15 +309,15 @@ player_check_decoder_startup(struct player *player)
|
|||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
|
|
||||||
if (audio_format_defined(&player->play_audio_format) &&
|
if (audio_format_defined(&player->play_audio_format) &&
|
||||||
!audio_output_all_wait(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 */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
pc.total_time = real_song_duration(dc->song, dc->total_time);
|
pc->total_time = real_song_duration(dc->song, dc->total_time);
|
||||||
pc.audio_format = dc->in_audio_format;
|
pc->audio_format = dc->in_audio_format;
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
player->play_audio_format = dc->out_audio_format;
|
player->play_audio_format = dc->out_audio_format;
|
||||||
player->decoder_starting = false;
|
player->decoder_starting = false;
|
||||||
@ -323,13 +330,13 @@ player_check_decoder_startup(struct player *player)
|
|||||||
"while playing \"%s\"", uri);
|
"while playing \"%s\"", uri);
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
pc.error = PLAYER_ERROR_AUDIO;
|
pc->error = PLAYER_ERROR_AUDIO;
|
||||||
|
|
||||||
/* pause: the user may resume playback as soon
|
/* pause: the user may resume playback as soon
|
||||||
as an audio output becomes available */
|
as an audio output becomes available */
|
||||||
pc.state = PLAYER_STATE_PAUSE;
|
pc->state = PLAYER_STATE_PAUSE;
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
player->paused = true;
|
player->paused = true;
|
||||||
return true;
|
return true;
|
||||||
@ -339,7 +346,7 @@ player_check_decoder_startup(struct player *player)
|
|||||||
} else {
|
} else {
|
||||||
/* the decoder is not yet ready; wait
|
/* the decoder is not yet ready; wait
|
||||||
some more */
|
some more */
|
||||||
player_wait_decoder(dc);
|
player_wait_decoder(pc, dc);
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -393,10 +400,11 @@ player_send_silence(struct player *player)
|
|||||||
*/
|
*/
|
||||||
static bool player_seek_decoder(struct player *player)
|
static bool player_seek_decoder(struct player *player)
|
||||||
{
|
{
|
||||||
struct song *song = pc.next_song;
|
struct player_control *pc = player->pc;
|
||||||
|
struct song *song = pc->next_song;
|
||||||
struct decoder_control *dc = player->dc;
|
struct decoder_control *dc = player->dc;
|
||||||
|
|
||||||
assert(pc.next_song != NULL);
|
assert(pc->next_song != NULL);
|
||||||
|
|
||||||
if (decoder_current_song(dc) != song) {
|
if (decoder_current_song(dc) != song) {
|
||||||
/* the decoder is already decoding the "next" song -
|
/* the decoder is already decoding the "next" song -
|
||||||
@ -412,7 +420,7 @@ static bool player_seek_decoder(struct player *player)
|
|||||||
player_dc_start(player, player->pipe);
|
player_dc_start(player, player->pipe);
|
||||||
if (!player_wait_for_decoder(player)) {
|
if (!player_wait_for_decoder(player)) {
|
||||||
/* decoder failure */
|
/* decoder failure */
|
||||||
player_command_finished();
|
player_command_finished(pc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -424,7 +432,7 @@ static bool player_seek_decoder(struct player *player)
|
|||||||
player->pipe = dc->pipe;
|
player->pipe = dc->pipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.next_song = NULL;
|
pc->next_song = NULL;
|
||||||
player->queued = false;
|
player->queued = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,28 +441,28 @@ static bool player_seek_decoder(struct player *player)
|
|||||||
while (player->decoder_starting) {
|
while (player->decoder_starting) {
|
||||||
if (!player_check_decoder_startup(player)) {
|
if (!player_check_decoder_startup(player)) {
|
||||||
/* decoder failure */
|
/* decoder failure */
|
||||||
player_command_finished();
|
player_command_finished(pc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send the SEEK command */
|
/* send the SEEK command */
|
||||||
|
|
||||||
double where = pc.seek_where;
|
double where = pc->seek_where;
|
||||||
if (where > pc.total_time)
|
if (where > pc->total_time)
|
||||||
where = pc.total_time - 0.1;
|
where = pc->total_time - 0.1;
|
||||||
if (where < 0.0)
|
if (where < 0.0)
|
||||||
where = 0.0;
|
where = 0.0;
|
||||||
|
|
||||||
if (!dc_seek(dc, where + song->start_ms / 1000.0)) {
|
if (!dc_seek(dc, where + song->start_ms / 1000.0)) {
|
||||||
/* decoder failure */
|
/* decoder failure */
|
||||||
player_command_finished();
|
player_command_finished(pc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
player->elapsed_time = where;
|
player->elapsed_time = where;
|
||||||
|
|
||||||
player_command_finished();
|
player_command_finished(pc);
|
||||||
|
|
||||||
player->xfade = XFADE_UNKNOWN;
|
player->xfade = XFADE_UNKNOWN;
|
||||||
|
|
||||||
@ -471,9 +479,10 @@ static bool player_seek_decoder(struct player *player)
|
|||||||
*/
|
*/
|
||||||
static void player_process_command(struct player *player)
|
static void player_process_command(struct player *player)
|
||||||
{
|
{
|
||||||
|
struct player_control *pc = player->pc;
|
||||||
G_GNUC_UNUSED struct decoder_control *dc = player->dc;
|
G_GNUC_UNUSED struct decoder_control *dc = player->dc;
|
||||||
|
|
||||||
switch (pc.command) {
|
switch (pc->command) {
|
||||||
case PLAYER_COMMAND_NONE:
|
case PLAYER_COMMAND_NONE:
|
||||||
case PLAYER_COMMAND_STOP:
|
case PLAYER_COMMAND_STOP:
|
||||||
case PLAYER_COMMAND_EXIT:
|
case PLAYER_COMMAND_EXIT:
|
||||||
@ -481,95 +490,95 @@ static void player_process_command(struct player *player)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_UPDATE_AUDIO:
|
case PLAYER_COMMAND_UPDATE_AUDIO:
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
audio_output_all_enable_disable();
|
audio_output_all_enable_disable();
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_QUEUE:
|
case PLAYER_COMMAND_QUEUE:
|
||||||
assert(pc.next_song != NULL);
|
assert(pc->next_song != NULL);
|
||||||
assert(!player->queued);
|
assert(!player->queued);
|
||||||
assert(!player_dc_at_next_song(player));
|
assert(!player_dc_at_next_song(player));
|
||||||
|
|
||||||
player->queued = true;
|
player->queued = true;
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_PAUSE:
|
case PLAYER_COMMAND_PAUSE:
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
player->paused = !player->paused;
|
player->paused = !player->paused;
|
||||||
if (player->paused) {
|
if (player->paused) {
|
||||||
audio_output_all_pause();
|
audio_output_all_pause();
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
pc.state = PLAYER_STATE_PAUSE;
|
pc->state = PLAYER_STATE_PAUSE;
|
||||||
} else if (!audio_format_defined(&player->play_audio_format)) {
|
} else if (!audio_format_defined(&player->play_audio_format)) {
|
||||||
/* the decoder hasn't provided an audio format
|
/* the decoder hasn't provided an audio format
|
||||||
yet - don't open the audio device yet */
|
yet - don't open the audio device yet */
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
pc.state = PLAYER_STATE_PLAY;
|
pc->state = PLAYER_STATE_PLAY;
|
||||||
} else if (audio_output_all_open(&player->play_audio_format, player_buffer)) {
|
} else if (audio_output_all_open(&player->play_audio_format, player_buffer)) {
|
||||||
/* unpaused, continue playing */
|
/* unpaused, continue playing */
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
pc.state = PLAYER_STATE_PLAY;
|
pc->state = PLAYER_STATE_PLAY;
|
||||||
} else {
|
} else {
|
||||||
/* the audio device has failed - rollback to
|
/* the audio device has failed - rollback to
|
||||||
pause mode */
|
pause mode */
|
||||||
pc.error = PLAYER_ERROR_AUDIO;
|
pc->error = PLAYER_ERROR_AUDIO;
|
||||||
|
|
||||||
player->paused = true;
|
player->paused = true;
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_SEEK:
|
case PLAYER_COMMAND_SEEK:
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
player_seek_decoder(player);
|
player_seek_decoder(player);
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_CANCEL:
|
case PLAYER_COMMAND_CANCEL:
|
||||||
if (pc.next_song == NULL) {
|
if (pc->next_song == NULL) {
|
||||||
/* the cancel request arrived too late, we're
|
/* the cancel request arrived too late, we're
|
||||||
already playing the queued song... stop
|
already playing the queued song... stop
|
||||||
everything now */
|
everything now */
|
||||||
pc.command = PLAYER_COMMAND_STOP;
|
pc->command = PLAYER_COMMAND_STOP;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player_dc_at_next_song(player)) {
|
if (player_dc_at_next_song(player)) {
|
||||||
/* the decoder is already decoding the song -
|
/* the decoder is already decoding the song -
|
||||||
stop it and reset the position */
|
stop it and reset the position */
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
player_dc_stop(player);
|
player_dc_stop(player);
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.next_song = NULL;
|
pc->next_song = NULL;
|
||||||
player->queued = false;
|
player->queued = false;
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_REFRESH:
|
case PLAYER_COMMAND_REFRESH:
|
||||||
if (audio_format_defined(&player->play_audio_format) &&
|
if (audio_format_defined(&player->play_audio_format) &&
|
||||||
!player->paused) {
|
!player->paused) {
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
audio_output_all_check();
|
audio_output_all_check();
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.elapsed_time = audio_output_all_get_elapsed_time();
|
pc->elapsed_time = audio_output_all_get_elapsed_time();
|
||||||
if (pc.elapsed_time < 0.0)
|
if (pc->elapsed_time < 0.0)
|
||||||
pc.elapsed_time = player->elapsed_time;
|
pc->elapsed_time = player->elapsed_time;
|
||||||
|
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -605,7 +614,8 @@ update_song_tag(struct song *song, const struct tag *new_tag)
|
|||||||
* Player lock is not held.
|
* Player lock is not held.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
play_chunk(struct song *song, struct music_chunk *chunk,
|
play_chunk(struct player_control *pc,
|
||||||
|
struct song *song, struct music_chunk *chunk,
|
||||||
const struct audio_format *format)
|
const struct audio_format *format)
|
||||||
{
|
{
|
||||||
assert(music_chunk_check_format(chunk, format));
|
assert(music_chunk_check_format(chunk, format));
|
||||||
@ -618,14 +628,14 @@ play_chunk(struct song *song, struct music_chunk *chunk,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.bit_rate = chunk->bit_rate;
|
pc->bit_rate = chunk->bit_rate;
|
||||||
|
|
||||||
/* send the chunk to the audio outputs */
|
/* send the chunk to the audio outputs */
|
||||||
|
|
||||||
if (!audio_output_all_play(chunk))
|
if (!audio_output_all_play(chunk))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pc.total_play_time += (double)chunk->length /
|
pc->total_play_time += (double)chunk->length /
|
||||||
audio_format_time_to_size(format);
|
audio_format_time_to_size(format);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -639,9 +649,10 @@ play_chunk(struct song *song, struct music_chunk *chunk,
|
|||||||
static bool
|
static bool
|
||||||
play_next_chunk(struct player *player)
|
play_next_chunk(struct player *player)
|
||||||
{
|
{
|
||||||
|
struct player_control *pc = player->pc;
|
||||||
struct decoder_control *dc = player->dc;
|
struct decoder_control *dc = player->dc;
|
||||||
|
|
||||||
if (!audio_output_all_wait(64))
|
if (!audio_output_all_wait(pc, 64))
|
||||||
/* the output pipe is still large enough, don't send
|
/* the output pipe is still large enough, don't send
|
||||||
another chunk */
|
another chunk */
|
||||||
return true;
|
return true;
|
||||||
@ -678,7 +689,7 @@ play_next_chunk(struct player *player)
|
|||||||
other_chunk->tag);
|
other_chunk->tag);
|
||||||
other_chunk->tag = NULL;
|
other_chunk->tag = NULL;
|
||||||
|
|
||||||
if (isnan(pc.mixramp_delay_seconds)) {
|
if (isnan(pc->mixramp_delay_seconds)) {
|
||||||
chunk->mix_ratio = ((float)cross_fade_position)
|
chunk->mix_ratio = ((float)cross_fade_position)
|
||||||
/ player->cross_fade_chunks;
|
/ player->cross_fade_chunks;
|
||||||
} else {
|
} else {
|
||||||
@ -713,7 +724,7 @@ play_next_chunk(struct player *player)
|
|||||||
} else {
|
} else {
|
||||||
/* wait for the decoder */
|
/* wait for the decoder */
|
||||||
decoder_signal(dc);
|
decoder_signal(dc);
|
||||||
player_wait_decoder(dc);
|
player_wait_decoder(pc, dc);
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -736,19 +747,20 @@ play_next_chunk(struct player *player)
|
|||||||
|
|
||||||
/* play the current chunk */
|
/* play the current chunk */
|
||||||
|
|
||||||
if (!play_chunk(player->song, chunk, &player->play_audio_format)) {
|
if (!play_chunk(player->pc, player->song, chunk,
|
||||||
|
&player->play_audio_format)) {
|
||||||
music_buffer_return(player_buffer, chunk);
|
music_buffer_return(player_buffer, chunk);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
pc.error = PLAYER_ERROR_AUDIO;
|
pc->error = PLAYER_ERROR_AUDIO;
|
||||||
|
|
||||||
/* pause: the user may resume playback as soon as an
|
/* pause: the user may resume playback as soon as an
|
||||||
audio output becomes available */
|
audio output becomes available */
|
||||||
pc.state = PLAYER_STATE_PAUSE;
|
pc->state = PLAYER_STATE_PAUSE;
|
||||||
player->paused = true;
|
player->paused = true;
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -758,7 +770,7 @@ play_next_chunk(struct player *player)
|
|||||||
larger block at a time */
|
larger block at a time */
|
||||||
decoder_lock(dc);
|
decoder_lock(dc);
|
||||||
if (!decoder_is_idle(dc) &&
|
if (!decoder_is_idle(dc) &&
|
||||||
music_pipe_size(dc->pipe) <= (pc.buffered_before_play +
|
music_pipe_size(dc->pipe) <= (pc->buffered_before_play +
|
||||||
music_buffer_size(player_buffer) * 3) / 4)
|
music_buffer_size(player_buffer) * 3) / 4)
|
||||||
decoder_signal(dc);
|
decoder_signal(dc);
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
@ -800,9 +812,10 @@ player_song_border(struct player *player)
|
|||||||
* basically a state machine, which multiplexes data between the
|
* basically a state machine, which multiplexes data between the
|
||||||
* decoder thread and the output threads.
|
* decoder thread and the output threads.
|
||||||
*/
|
*/
|
||||||
static void do_play(struct decoder_control *dc)
|
static void do_play(struct player_control *pc, struct decoder_control *dc)
|
||||||
{
|
{
|
||||||
struct player player = {
|
struct player player = {
|
||||||
|
.pc = pc,
|
||||||
.dc = dc,
|
.dc = dc,
|
||||||
.buffering = true,
|
.buffering = true,
|
||||||
.decoder_starting = false,
|
.decoder_starting = false,
|
||||||
@ -816,42 +829,42 @@ static void do_play(struct decoder_control *dc)
|
|||||||
.elapsed_time = 0.0,
|
.elapsed_time = 0.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
player.pipe = music_pipe_new();
|
player.pipe = music_pipe_new();
|
||||||
|
|
||||||
player_dc_start(&player, player.pipe);
|
player_dc_start(&player, player.pipe);
|
||||||
if (!player_wait_for_decoder(&player)) {
|
if (!player_wait_for_decoder(&player)) {
|
||||||
player_dc_stop(&player);
|
player_dc_stop(&player);
|
||||||
player_command_finished();
|
player_command_finished(pc);
|
||||||
music_pipe_free(player.pipe);
|
music_pipe_free(player.pipe);
|
||||||
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
pc.state = PLAYER_STATE_PLAY;
|
pc->state = PLAYER_STATE_PLAY;
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
player_process_command(&player);
|
player_process_command(&player);
|
||||||
if (pc.command == PLAYER_COMMAND_STOP ||
|
if (pc->command == PLAYER_COMMAND_STOP ||
|
||||||
pc.command == PLAYER_COMMAND_EXIT ||
|
pc->command == PLAYER_COMMAND_EXIT ||
|
||||||
pc.command == PLAYER_COMMAND_CLOSE_AUDIO) {
|
pc->command == PLAYER_COMMAND_CLOSE_AUDIO) {
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
audio_output_all_cancel();
|
audio_output_all_cancel();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
if (player.buffering) {
|
if (player.buffering) {
|
||||||
/* buffering at the start of the song - wait
|
/* buffering at the start of the song - wait
|
||||||
until the buffer is large enough, to
|
until the buffer is large enough, to
|
||||||
prevent stuttering on slow machines */
|
prevent stuttering on slow machines */
|
||||||
|
|
||||||
if (music_pipe_size(player.pipe) < pc.buffered_before_play &&
|
if (music_pipe_size(player.pipe) < pc->buffered_before_play &&
|
||||||
!decoder_lock_is_idle(dc)) {
|
!decoder_lock_is_idle(dc)) {
|
||||||
/* not enough decoded buffer space yet */
|
/* not enough decoded buffer space yet */
|
||||||
|
|
||||||
@ -863,9 +876,9 @@ static void do_play(struct decoder_control *dc)
|
|||||||
|
|
||||||
decoder_lock(dc);
|
decoder_lock(dc);
|
||||||
/* XXX race condition: check decoder again */
|
/* XXX race condition: check decoder again */
|
||||||
player_wait_decoder(dc);
|
player_wait_decoder(pc, dc);
|
||||||
decoder_unlock(dc);
|
decoder_unlock(dc);
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
/* buffering is complete */
|
/* buffering is complete */
|
||||||
@ -889,7 +902,7 @@ static void do_play(struct decoder_control *dc)
|
|||||||
!dc_seek(dc, song->start_ms / 1000.0))
|
!dc_seek(dc, song->start_ms / 1000.0))
|
||||||
player_dc_stop(&player);
|
player_dc_stop(&player);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -918,9 +931,9 @@ static void do_play(struct decoder_control *dc)
|
|||||||
calculate how many chunks will be required
|
calculate how many chunks will be required
|
||||||
for it */
|
for it */
|
||||||
player.cross_fade_chunks =
|
player.cross_fade_chunks =
|
||||||
cross_fade_calc(pc.cross_fade_seconds, dc->total_time,
|
cross_fade_calc(pc->cross_fade_seconds, dc->total_time,
|
||||||
pc.mixramp_db,
|
pc->mixramp_db,
|
||||||
pc.mixramp_delay_seconds,
|
pc->mixramp_delay_seconds,
|
||||||
dc->replay_gain_db,
|
dc->replay_gain_db,
|
||||||
dc->replay_gain_prev_db,
|
dc->replay_gain_prev_db,
|
||||||
dc->mixramp_start,
|
dc->mixramp_start,
|
||||||
@ -928,7 +941,7 @@ static void do_play(struct decoder_control *dc)
|
|||||||
&dc->out_audio_format,
|
&dc->out_audio_format,
|
||||||
&player.play_audio_format,
|
&player.play_audio_format,
|
||||||
music_buffer_size(player_buffer) -
|
music_buffer_size(player_buffer) -
|
||||||
pc.buffered_before_play);
|
pc->buffered_before_play);
|
||||||
if (player.cross_fade_chunks > 0) {
|
if (player.cross_fade_chunks > 0) {
|
||||||
player.xfade = XFADE_ENABLED;
|
player.xfade = XFADE_ENABLED;
|
||||||
player.cross_fading = false;
|
player.cross_fading = false;
|
||||||
@ -939,10 +952,10 @@ static void do_play(struct decoder_control *dc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (player.paused) {
|
if (player.paused) {
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
if (pc.command == PLAYER_COMMAND_NONE)
|
if (pc->command == PLAYER_COMMAND_NONE)
|
||||||
player_wait();
|
player_wait(pc);
|
||||||
continue;
|
continue;
|
||||||
} else if (!music_pipe_empty(player.pipe)) {
|
} else if (!music_pipe_empty(player.pipe)) {
|
||||||
/* at least one music chunk is ready - send it
|
/* at least one music chunk is ready - send it
|
||||||
@ -979,7 +992,7 @@ static void do_play(struct decoder_control *dc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
player_dc_stop(&player);
|
player_dc_stop(&player);
|
||||||
@ -990,113 +1003,116 @@ static void do_play(struct decoder_control *dc)
|
|||||||
if (player.cross_fade_tag != NULL)
|
if (player.cross_fade_tag != NULL)
|
||||||
tag_free(player.cross_fade_tag);
|
tag_free(player.cross_fade_tag);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
if (player.queued) {
|
if (player.queued) {
|
||||||
assert(pc.next_song != NULL);
|
assert(pc->next_song != NULL);
|
||||||
pc.next_song = NULL;
|
pc->next_song = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.state = PLAYER_STATE_STOP;
|
pc->state = PLAYER_STATE_STOP;
|
||||||
|
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gpointer player_task(G_GNUC_UNUSED gpointer arg)
|
static gpointer
|
||||||
|
player_task(gpointer arg)
|
||||||
{
|
{
|
||||||
|
struct player_control *pc = arg;
|
||||||
struct decoder_control dc;
|
struct decoder_control dc;
|
||||||
|
|
||||||
dc_init(&dc);
|
dc_init(&dc, pc);
|
||||||
decoder_thread_start(&dc);
|
decoder_thread_start(&dc);
|
||||||
|
|
||||||
player_buffer = music_buffer_new(pc.buffer_chunks);
|
player_buffer = music_buffer_new(pc->buffer_chunks);
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
switch (pc.command) {
|
switch (pc->command) {
|
||||||
case PLAYER_COMMAND_QUEUE:
|
case PLAYER_COMMAND_QUEUE:
|
||||||
assert(pc.next_song != NULL);
|
assert(pc->next_song != NULL);
|
||||||
|
|
||||||
do_play(&dc);
|
do_play(pc, &dc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_STOP:
|
case PLAYER_COMMAND_STOP:
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
audio_output_all_cancel();
|
audio_output_all_cancel();
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case PLAYER_COMMAND_SEEK:
|
case PLAYER_COMMAND_SEEK:
|
||||||
case PLAYER_COMMAND_PAUSE:
|
case PLAYER_COMMAND_PAUSE:
|
||||||
pc.next_song = NULL;
|
pc->next_song = NULL;
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_CLOSE_AUDIO:
|
case PLAYER_COMMAND_CLOSE_AUDIO:
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
audio_output_all_release();
|
audio_output_all_release();
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
/* in the DEBUG build, check for leaked
|
/* in the DEBUG build, check for leaked
|
||||||
music_chunk objects by freeing the
|
music_chunk objects by freeing the
|
||||||
music_buffer */
|
music_buffer */
|
||||||
music_buffer_free(player_buffer);
|
music_buffer_free(player_buffer);
|
||||||
player_buffer = music_buffer_new(pc.buffer_chunks);
|
player_buffer = music_buffer_new(pc->buffer_chunks);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_UPDATE_AUDIO:
|
case PLAYER_COMMAND_UPDATE_AUDIO:
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
audio_output_all_enable_disable();
|
audio_output_all_enable_disable();
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_EXIT:
|
case PLAYER_COMMAND_EXIT:
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
dc_quit(&dc);
|
dc_quit(&dc);
|
||||||
dc_deinit(&dc);
|
dc_deinit(&dc);
|
||||||
audio_output_all_close();
|
audio_output_all_close();
|
||||||
music_buffer_free(player_buffer);
|
music_buffer_free(player_buffer);
|
||||||
|
|
||||||
player_command_finished();
|
player_command_finished(pc);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
case PLAYER_COMMAND_CANCEL:
|
case PLAYER_COMMAND_CANCEL:
|
||||||
pc.next_song = NULL;
|
pc->next_song = NULL;
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_REFRESH:
|
case PLAYER_COMMAND_REFRESH:
|
||||||
/* no-op when not playing */
|
/* no-op when not playing */
|
||||||
player_command_finished_locked();
|
player_command_finished_locked(pc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLAYER_COMMAND_NONE:
|
case PLAYER_COMMAND_NONE:
|
||||||
player_wait();
|
player_wait(pc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void player_create(void)
|
void
|
||||||
|
player_create(struct player_control *pc)
|
||||||
{
|
{
|
||||||
assert(pc.thread == NULL);
|
assert(pc->thread == NULL);
|
||||||
|
|
||||||
GError *e = NULL;
|
GError *e = NULL;
|
||||||
pc.thread = g_thread_create(player_task, NULL, true, &e);
|
pc->thread = g_thread_create(player_task, pc, true, &e);
|
||||||
if (pc.thread == NULL)
|
if (pc->thread == NULL)
|
||||||
MPD_ERROR("Failed to spawn player task: %s", e->message);
|
MPD_ERROR("Failed to spawn player task: %s", e->message);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
#ifndef MPD_PLAYER_THREAD_H
|
#ifndef MPD_PLAYER_THREAD_H
|
||||||
#define MPD_PLAYER_THREAD_H
|
#define MPD_PLAYER_THREAD_H
|
||||||
|
|
||||||
void player_create(void);
|
struct player_control;
|
||||||
|
|
||||||
|
void
|
||||||
|
player_create(struct player_control *pc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -75,7 +75,8 @@ playlist_finish(struct playlist *playlist)
|
|||||||
* Queue a song, addressed by its order number.
|
* Queue a song, addressed by its order number.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
playlist_queue_song_order(struct playlist *playlist, unsigned order)
|
playlist_queue_song_order(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned order)
|
||||||
{
|
{
|
||||||
struct song *song;
|
struct song *song;
|
||||||
char *uri;
|
char *uri;
|
||||||
@ -89,16 +90,16 @@ playlist_queue_song_order(struct playlist *playlist, unsigned order)
|
|||||||
g_debug("queue song %i:\"%s\"", playlist->queued, uri);
|
g_debug("queue song %i:\"%s\"", playlist->queued, uri);
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
|
|
||||||
pc_enqueue_song(song);
|
pc_enqueue_song(pc, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called if the player thread has started playing the "queued" song.
|
* Called if the player thread has started playing the "queued" song.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
playlist_song_started(struct playlist *playlist)
|
playlist_song_started(struct playlist *playlist, struct player_control *pc)
|
||||||
{
|
{
|
||||||
assert(pc.next_song == NULL);
|
assert(pc->next_song == NULL);
|
||||||
assert(playlist->queued >= -1);
|
assert(playlist->queued >= -1);
|
||||||
|
|
||||||
/* queued song has started: copy queued to current,
|
/* queued song has started: copy queued to current,
|
||||||
@ -110,11 +111,13 @@ playlist_song_started(struct playlist *playlist)
|
|||||||
|
|
||||||
/* Pause if we are in single mode. */
|
/* Pause if we are in single mode. */
|
||||||
if(playlist->queue.single && !playlist->queue.repeat) {
|
if(playlist->queue.single && !playlist->queue.repeat) {
|
||||||
pc_set_pause(true);
|
pc_set_pause(pc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(playlist->queue.consume)
|
if(playlist->queue.consume)
|
||||||
playlist_delete(playlist, queue_order_to_position(&playlist->queue, current));
|
playlist_delete(playlist, pc,
|
||||||
|
queue_order_to_position(&playlist->queue,
|
||||||
|
current));
|
||||||
|
|
||||||
idle_add(IDLE_PLAYER);
|
idle_add(IDLE_PLAYER);
|
||||||
}
|
}
|
||||||
@ -129,7 +132,9 @@ playlist_get_queued_song(struct playlist *playlist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_update_queued_song(struct playlist *playlist, const struct song *prev)
|
playlist_update_queued_song(struct playlist *playlist,
|
||||||
|
struct player_control *pc,
|
||||||
|
const struct song *prev)
|
||||||
{
|
{
|
||||||
int next_order;
|
int next_order;
|
||||||
const struct song *next_song;
|
const struct song *next_song;
|
||||||
@ -170,20 +175,21 @@ playlist_update_queued_song(struct playlist *playlist, const struct song *prev)
|
|||||||
|
|
||||||
if (prev != NULL && next_song != prev) {
|
if (prev != NULL && next_song != prev) {
|
||||||
/* clear the currently queued song */
|
/* clear the currently queued song */
|
||||||
pc_cancel();
|
pc_cancel(pc);
|
||||||
playlist->queued = -1;
|
playlist->queued = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_order >= 0) {
|
if (next_order >= 0) {
|
||||||
if (next_song != prev)
|
if (next_song != prev)
|
||||||
playlist_queue_song_order(playlist, next_order);
|
playlist_queue_song_order(playlist, pc, next_order);
|
||||||
else
|
else
|
||||||
playlist->queued = next_order;
|
playlist->queued = next_order;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_play_order(struct playlist *playlist, int orderNum)
|
playlist_play_order(struct playlist *playlist, struct player_control *pc,
|
||||||
|
int orderNum)
|
||||||
{
|
{
|
||||||
struct song *song;
|
struct song *song;
|
||||||
char *uri;
|
char *uri;
|
||||||
@ -197,46 +203,46 @@ playlist_play_order(struct playlist *playlist, int orderNum)
|
|||||||
g_debug("play %i:\"%s\"", orderNum, uri);
|
g_debug("play %i:\"%s\"", orderNum, uri);
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
|
|
||||||
pc_play(song);
|
pc_play(pc, song);
|
||||||
playlist->current = orderNum;
|
playlist->current = orderNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
playlist_resume_playback(struct playlist *playlist);
|
playlist_resume_playback(struct playlist *playlist, struct player_control *pc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the "PLAYLIST" event handler. It is invoked by the player
|
* This is the "PLAYLIST" event handler. It is invoked by the player
|
||||||
* thread whenever it requests a new queued song, or when it exits.
|
* thread whenever it requests a new queued song, or when it exits.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
playlist_sync(struct playlist *playlist)
|
playlist_sync(struct playlist *playlist, struct player_control *pc)
|
||||||
{
|
{
|
||||||
if (!playlist->playing)
|
if (!playlist->playing)
|
||||||
/* this event has reached us out of sync: we aren't
|
/* this event has reached us out of sync: we aren't
|
||||||
playing anymore; ignore the event */
|
playing anymore; ignore the event */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
player_lock();
|
player_lock(pc);
|
||||||
enum player_state pc_state = pc_get_state();
|
enum player_state pc_state = pc_get_state(pc);
|
||||||
const struct song *pc_next_song = pc.next_song;
|
const struct song *pc_next_song = pc->next_song;
|
||||||
player_unlock();
|
player_unlock(pc);
|
||||||
|
|
||||||
if (pc_state == PLAYER_STATE_STOP)
|
if (pc_state == PLAYER_STATE_STOP)
|
||||||
/* the player thread has stopped: check if playback
|
/* the player thread has stopped: check if playback
|
||||||
should be restarted with the next song. That can
|
should be restarted with the next song. That can
|
||||||
happen if the playlist isn't filling the queue fast
|
happen if the playlist isn't filling the queue fast
|
||||||
enough */
|
enough */
|
||||||
playlist_resume_playback(playlist);
|
playlist_resume_playback(playlist, pc);
|
||||||
else {
|
else {
|
||||||
/* check if the player thread has already started
|
/* check if the player thread has already started
|
||||||
playing the queued song */
|
playing the queued song */
|
||||||
if (pc_next_song == NULL && playlist->queued != -1)
|
if (pc_next_song == NULL && playlist->queued != -1)
|
||||||
playlist_song_started(playlist);
|
playlist_song_started(playlist, pc);
|
||||||
|
|
||||||
/* make sure the queued song is always set (if
|
/* make sure the queued song is always set (if
|
||||||
possible) */
|
possible) */
|
||||||
if (pc.next_song == NULL && playlist->queued < 0)
|
if (pc->next_song == NULL && playlist->queued < 0)
|
||||||
playlist_update_queued_song(playlist, NULL);
|
playlist_update_queued_song(playlist, pc, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,14 +251,14 @@ playlist_sync(struct playlist *playlist)
|
|||||||
* decide whether to re-start playback
|
* decide whether to re-start playback
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
playlist_resume_playback(struct playlist *playlist)
|
playlist_resume_playback(struct playlist *playlist, struct player_control *pc)
|
||||||
{
|
{
|
||||||
enum player_error error;
|
enum player_error error;
|
||||||
|
|
||||||
assert(playlist->playing);
|
assert(playlist->playing);
|
||||||
assert(pc_get_state() == PLAYER_STATE_STOP);
|
assert(pc_get_state(pc) == PLAYER_STATE_STOP);
|
||||||
|
|
||||||
error = pc_get_error();
|
error = pc_get_error(pc);
|
||||||
if (error == PLAYER_ERROR_NOERROR)
|
if (error == PLAYER_ERROR_NOERROR)
|
||||||
playlist->error_count = 0;
|
playlist->error_count = 0;
|
||||||
else
|
else
|
||||||
@ -263,10 +269,10 @@ playlist_resume_playback(struct playlist *playlist)
|
|||||||
playlist->error_count >= queue_length(&playlist->queue))
|
playlist->error_count >= queue_length(&playlist->queue))
|
||||||
/* too many errors, or critical error: stop
|
/* too many errors, or critical error: stop
|
||||||
playback */
|
playback */
|
||||||
playlist_stop(playlist);
|
playlist_stop(playlist, pc);
|
||||||
else
|
else
|
||||||
/* continue playback at the next song */
|
/* continue playback at the next song */
|
||||||
playlist_next(playlist);
|
playlist_next(playlist, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -294,7 +300,8 @@ playlist_get_consume(const struct playlist *playlist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_repeat(struct playlist *playlist, bool status)
|
playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
|
||||||
|
bool status)
|
||||||
{
|
{
|
||||||
if (status == playlist->queue.repeat)
|
if (status == playlist->queue.repeat)
|
||||||
return;
|
return;
|
||||||
@ -303,7 +310,7 @@ playlist_set_repeat(struct playlist *playlist, bool status)
|
|||||||
|
|
||||||
/* if the last song is currently being played, the "next song"
|
/* if the last song is currently being played, the "next song"
|
||||||
might change when repeat mode is toggled */
|
might change when repeat mode is toggled */
|
||||||
playlist_update_queued_song(playlist,
|
playlist_update_queued_song(playlist, pc,
|
||||||
playlist_get_queued_song(playlist));
|
playlist_get_queued_song(playlist));
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
@ -321,7 +328,8 @@ playlist_order(struct playlist *playlist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_single(struct playlist *playlist, bool status)
|
playlist_set_single(struct playlist *playlist, struct player_control *pc,
|
||||||
|
bool status)
|
||||||
{
|
{
|
||||||
if (status == playlist->queue.single)
|
if (status == playlist->queue.single)
|
||||||
return;
|
return;
|
||||||
@ -330,7 +338,7 @@ playlist_set_single(struct playlist *playlist, bool status)
|
|||||||
|
|
||||||
/* if the last song is currently being played, the "next song"
|
/* if the last song is currently being played, the "next song"
|
||||||
might change when single mode is toggled */
|
might change when single mode is toggled */
|
||||||
playlist_update_queued_song(playlist,
|
playlist_update_queued_song(playlist, pc,
|
||||||
playlist_get_queued_song(playlist));
|
playlist_get_queued_song(playlist));
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
@ -347,7 +355,8 @@ playlist_set_consume(struct playlist *playlist, bool status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_random(struct playlist *playlist, bool status)
|
playlist_set_random(struct playlist *playlist, struct player_control *pc,
|
||||||
|
bool status)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
const struct song *queued;
|
||||||
|
|
||||||
@ -384,7 +393,7 @@ playlist_set_random(struct playlist *playlist, bool status)
|
|||||||
} else
|
} else
|
||||||
playlist_order(playlist);
|
playlist_order(playlist);
|
||||||
|
|
||||||
playlist_update_queued_song(playlist, queued);
|
playlist_update_queued_song(playlist, pc, queued);
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#define PLAYLIST_COMMENT '#'
|
#define PLAYLIST_COMMENT '#'
|
||||||
|
|
||||||
|
struct player_control;
|
||||||
|
|
||||||
enum playlist_result {
|
enum playlist_result {
|
||||||
PLAYLIST_RESULT_SUCCESS,
|
PLAYLIST_RESULT_SUCCESS,
|
||||||
PLAYLIST_RESULT_ERRNO,
|
PLAYLIST_RESULT_ERRNO,
|
||||||
@ -111,7 +113,7 @@ playlist_get_queue(const struct playlist *playlist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_clear(struct playlist *playlist);
|
playlist_clear(struct playlist *playlist, struct player_control *pc);
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
/**
|
/**
|
||||||
@ -119,20 +121,21 @@ playlist_clear(struct playlist *playlist);
|
|||||||
* but only if the file's owner is equal to the specified uid.
|
* but only if the file's owner is equal to the specified uid.
|
||||||
*/
|
*/
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_file(struct playlist *playlist, const char *path, int uid,
|
playlist_append_file(struct playlist *playlist, struct player_control *pc,
|
||||||
unsigned *added_id);
|
const char *path, int uid, unsigned *added_id);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_uri(struct playlist *playlist, const char *file,
|
playlist_append_uri(struct playlist *playlist, struct player_control *pc,
|
||||||
unsigned *added_id);
|
const char *file, unsigned *added_id);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_song(struct playlist *playlist,
|
playlist_append_song(struct playlist *playlist, struct player_control *pc,
|
||||||
struct song *song, unsigned *added_id);
|
struct song *song, unsigned *added_id);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete(struct playlist *playlist, unsigned song);
|
playlist_delete(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a range of songs from the playlist.
|
* Deletes a range of songs from the playlist.
|
||||||
@ -141,64 +144,77 @@ playlist_delete(struct playlist *playlist, unsigned song);
|
|||||||
* @param end the position after the last song to delete
|
* @param end the position after the last song to delete
|
||||||
*/
|
*/
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end);
|
playlist_delete_range(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned start, unsigned end);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete_id(struct playlist *playlist, unsigned song);
|
playlist_delete_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned song);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_stop(struct playlist *playlist);
|
playlist_stop(struct playlist *playlist, struct player_control *pc);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_play(struct playlist *playlist, int song);
|
playlist_play(struct playlist *playlist, struct player_control *pc,
|
||||||
|
int song);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_play_id(struct playlist *playlist, int song);
|
playlist_play_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
int song);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_next(struct playlist *playlist);
|
playlist_next(struct playlist *playlist, struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_sync(struct playlist *playlist);
|
playlist_sync(struct playlist *playlist, struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_previous(struct playlist *playlist);
|
playlist_previous(struct playlist *playlist, struct player_control *pc);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end);
|
playlist_shuffle(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned start, unsigned end);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_delete_song(struct playlist *playlist, const struct song *song);
|
playlist_delete_song(struct playlist *playlist, struct player_control *pc,
|
||||||
|
const struct song *song);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_move_range(struct playlist *playlist, unsigned start, unsigned end, int to);
|
playlist_move_range(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned start, unsigned end, int to);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_move_id(struct playlist *playlist, unsigned id, int to);
|
playlist_move_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned id, int to);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2);
|
playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned song1, unsigned song2);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2);
|
playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned id1, unsigned id2);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_get_repeat(const struct playlist *playlist);
|
playlist_get_repeat(const struct playlist *playlist);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_repeat(struct playlist *playlist, bool status);
|
playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
|
||||||
|
bool status);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_get_random(const struct playlist *playlist);
|
playlist_get_random(const struct playlist *playlist);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_random(struct playlist *playlist, bool status);
|
playlist_set_random(struct playlist *playlist, struct player_control *pc,
|
||||||
|
bool status);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_get_single(const struct playlist *playlist);
|
playlist_get_single(const struct playlist *playlist);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_single(struct playlist *playlist, bool status);
|
playlist_set_single(struct playlist *playlist, struct player_control *pc,
|
||||||
|
bool status);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_get_consume(const struct playlist *playlist);
|
playlist_get_consume(const struct playlist *playlist);
|
||||||
@ -222,10 +238,11 @@ unsigned long
|
|||||||
playlist_get_version(const struct playlist *playlist);
|
playlist_get_version(const struct playlist *playlist);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time);
|
playlist_seek_song(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned song, float seek_time);
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_seek_song_id(struct playlist *playlist,
|
playlist_seek_song_id(struct playlist *playlist, struct player_control *pc,
|
||||||
unsigned id, float seek_time);
|
unsigned id, float seek_time);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
#undef G_LOG_DOMAIN
|
#undef G_LOG_DOMAIN
|
||||||
#define G_LOG_DOMAIN "playlist"
|
#define G_LOG_DOMAIN "playlist"
|
||||||
|
|
||||||
void playlist_stop(struct playlist *playlist)
|
void
|
||||||
|
playlist_stop(struct playlist *playlist, struct player_control *pc)
|
||||||
{
|
{
|
||||||
if (!playlist->playing)
|
if (!playlist->playing)
|
||||||
return;
|
return;
|
||||||
@ -40,7 +41,7 @@ void playlist_stop(struct playlist *playlist)
|
|||||||
assert(playlist->current >= 0);
|
assert(playlist->current >= 0);
|
||||||
|
|
||||||
g_debug("stop");
|
g_debug("stop");
|
||||||
pc_stop();
|
pc_stop(pc);
|
||||||
playlist->queued = -1;
|
playlist->queued = -1;
|
||||||
playlist->playing = false;
|
playlist->playing = false;
|
||||||
|
|
||||||
@ -62,11 +63,13 @@ void playlist_stop(struct playlist *playlist)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result playlist_play(struct playlist *playlist, int song)
|
enum playlist_result
|
||||||
|
playlist_play(struct playlist *playlist, struct player_control *pc,
|
||||||
|
int song)
|
||||||
{
|
{
|
||||||
unsigned i = song;
|
unsigned i = song;
|
||||||
|
|
||||||
pc_clear_error();
|
pc_clear_error(pc);
|
||||||
|
|
||||||
if (song == -1) {
|
if (song == -1) {
|
||||||
/* play any song ("current" song, or the first song */
|
/* play any song ("current" song, or the first song */
|
||||||
@ -77,7 +80,7 @@ enum playlist_result playlist_play(struct playlist *playlist, int song)
|
|||||||
if (playlist->playing) {
|
if (playlist->playing) {
|
||||||
/* already playing: unpause playback, just in
|
/* already playing: unpause playback, just in
|
||||||
case it was paused, and return */
|
case it was paused, and return */
|
||||||
pc_set_pause(false);
|
pc_set_pause(pc, false);
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,28 +112,29 @@ enum playlist_result playlist_play(struct playlist *playlist, int song)
|
|||||||
playlist->stop_on_error = false;
|
playlist->stop_on_error = false;
|
||||||
playlist->error_count = 0;
|
playlist->error_count = 0;
|
||||||
|
|
||||||
playlist_play_order(playlist, i);
|
playlist_play_order(playlist, pc, i);
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_play_id(struct playlist *playlist, int id)
|
playlist_play_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
int id)
|
||||||
{
|
{
|
||||||
int song;
|
int song;
|
||||||
|
|
||||||
if (id == -1) {
|
if (id == -1) {
|
||||||
return playlist_play(playlist, id);
|
return playlist_play(playlist, pc, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
song = queue_id_to_position(&playlist->queue, id);
|
song = queue_id_to_position(&playlist->queue, id);
|
||||||
if (song < 0)
|
if (song < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_play(playlist, song);
|
return playlist_play(playlist, pc, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_next(struct playlist *playlist)
|
playlist_next(struct playlist *playlist, struct player_control *pc)
|
||||||
{
|
{
|
||||||
int next_order;
|
int next_order;
|
||||||
int current;
|
int current;
|
||||||
@ -149,7 +153,7 @@ playlist_next(struct playlist *playlist)
|
|||||||
next_order = queue_next_order(&playlist->queue, playlist->current);
|
next_order = queue_next_order(&playlist->queue, playlist->current);
|
||||||
if (next_order < 0) {
|
if (next_order < 0) {
|
||||||
/* no song after this one: stop playback */
|
/* no song after this one: stop playback */
|
||||||
playlist_stop(playlist);
|
playlist_stop(playlist, pc);
|
||||||
|
|
||||||
/* reset "current song" */
|
/* reset "current song" */
|
||||||
playlist->current = -1;
|
playlist->current = -1;
|
||||||
@ -170,15 +174,18 @@ playlist_next(struct playlist *playlist)
|
|||||||
discard them anyway */
|
discard them anyway */
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_play_order(playlist, next_order);
|
playlist_play_order(playlist, pc, next_order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Consume mode removes each played songs. */
|
/* Consume mode removes each played songs. */
|
||||||
if(playlist->queue.consume)
|
if(playlist->queue.consume)
|
||||||
playlist_delete(playlist, queue_order_to_position(&playlist->queue, current));
|
playlist_delete(playlist, pc,
|
||||||
|
queue_order_to_position(&playlist->queue,
|
||||||
|
current));
|
||||||
}
|
}
|
||||||
|
|
||||||
void playlist_previous(struct playlist *playlist)
|
void
|
||||||
|
playlist_previous(struct playlist *playlist, struct player_control *pc)
|
||||||
{
|
{
|
||||||
if (!playlist->playing)
|
if (!playlist->playing)
|
||||||
return;
|
return;
|
||||||
@ -187,21 +194,22 @@ void playlist_previous(struct playlist *playlist)
|
|||||||
|
|
||||||
if (playlist->current > 0) {
|
if (playlist->current > 0) {
|
||||||
/* play the preceding song */
|
/* play the preceding song */
|
||||||
playlist_play_order(playlist,
|
playlist_play_order(playlist, pc,
|
||||||
playlist->current - 1);
|
playlist->current - 1);
|
||||||
} else if (playlist->queue.repeat) {
|
} else if (playlist->queue.repeat) {
|
||||||
/* play the last song in "repeat" mode */
|
/* play the last song in "repeat" mode */
|
||||||
playlist_play_order(playlist,
|
playlist_play_order(playlist, pc,
|
||||||
queue_length(&playlist->queue) - 1);
|
queue_length(&playlist->queue) - 1);
|
||||||
} else {
|
} else {
|
||||||
/* re-start playing the current song if it's
|
/* re-start playing the current song if it's
|
||||||
the first one */
|
the first one */
|
||||||
playlist_play_order(playlist, playlist->current);
|
playlist_play_order(playlist, pc, playlist->current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
|
playlist_seek_song(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned song, float seek_time)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
const struct song *queued;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@ -217,7 +225,7 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
|
|||||||
else
|
else
|
||||||
i = song;
|
i = song;
|
||||||
|
|
||||||
pc_clear_error();
|
pc_clear_error(pc);
|
||||||
playlist->stop_on_error = true;
|
playlist->stop_on_error = true;
|
||||||
playlist->error_count = 0;
|
playlist->error_count = 0;
|
||||||
|
|
||||||
@ -225,29 +233,30 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
|
|||||||
/* seeking is not within the current song - first
|
/* seeking is not within the current song - first
|
||||||
start playing the new song */
|
start playing the new song */
|
||||||
|
|
||||||
playlist_play_order(playlist, i);
|
playlist_play_order(playlist, pc, i);
|
||||||
queued = NULL;
|
queued = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = pc_seek(queue_get_order(&playlist->queue, i), seek_time);
|
success = pc_seek(pc, queue_get_order(&playlist->queue, i), seek_time);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
playlist_update_queued_song(playlist, queued);
|
playlist_update_queued_song(playlist, pc, queued);
|
||||||
|
|
||||||
return PLAYLIST_RESULT_NOT_PLAYING;
|
return PLAYLIST_RESULT_NOT_PLAYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist->queued = -1;
|
playlist->queued = -1;
|
||||||
playlist_update_queued_song(playlist, NULL);
|
playlist_update_queued_song(playlist, pc, NULL);
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_seek_song_id(struct playlist *playlist, unsigned id, float seek_time)
|
playlist_seek_song_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned id, float seek_time)
|
||||||
{
|
{
|
||||||
int song = queue_id_to_position(&playlist->queue, id);
|
int song = queue_id_to_position(&playlist->queue, id);
|
||||||
if (song < 0)
|
if (song < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_seek_song(playlist, song, seek_time);
|
return playlist_seek_song(playlist, pc, song, seek_time);
|
||||||
}
|
}
|
||||||
|
@ -43,16 +43,17 @@ static void playlist_increment_version(struct playlist *playlist)
|
|||||||
idle_add(IDLE_PLAYLIST);
|
idle_add(IDLE_PLAYLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void playlist_clear(struct playlist *playlist)
|
void
|
||||||
|
playlist_clear(struct playlist *playlist, struct player_control *pc)
|
||||||
{
|
{
|
||||||
playlist_stop(playlist);
|
playlist_stop(playlist, pc);
|
||||||
|
|
||||||
/* make sure there are no references to allocated songs
|
/* make sure there are no references to allocated songs
|
||||||
anymore */
|
anymore */
|
||||||
for (unsigned i = 0; i < queue_length(&playlist->queue); i++) {
|
for (unsigned i = 0; i < queue_length(&playlist->queue); i++) {
|
||||||
const struct song *song = queue_get(&playlist->queue, i);
|
const struct song *song = queue_get(&playlist->queue, i);
|
||||||
if (!song_in_database(song))
|
if (!song_in_database(song))
|
||||||
pc_song_deleted(song);
|
pc_song_deleted(pc, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_clear(&playlist->queue);
|
queue_clear(&playlist->queue);
|
||||||
@ -64,8 +65,8 @@ void playlist_clear(struct playlist *playlist)
|
|||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_file(struct playlist *playlist, const char *path, int uid,
|
playlist_append_file(struct playlist *playlist, struct player_control *pc,
|
||||||
unsigned *added_id)
|
const char *path, int uid, unsigned *added_id)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -87,12 +88,12 @@ playlist_append_file(struct playlist *playlist, const char *path, int uid,
|
|||||||
if (song == NULL)
|
if (song == NULL)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_append_song(playlist, song, added_id);
|
return playlist_append_song(playlist, pc, song, added_id);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_song(struct playlist *playlist,
|
playlist_append_song(struct playlist *playlist, struct player_control *pc,
|
||||||
struct song *song, unsigned *added_id)
|
struct song *song, unsigned *added_id)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
const struct song *queued;
|
||||||
@ -121,7 +122,7 @@ playlist_append_song(struct playlist *playlist,
|
|||||||
|
|
||||||
playlist_increment_version(playlist);
|
playlist_increment_version(playlist);
|
||||||
|
|
||||||
playlist_update_queued_song(playlist, queued);
|
playlist_update_queued_song(playlist, pc, queued);
|
||||||
|
|
||||||
if (added_id)
|
if (added_id)
|
||||||
*added_id = id;
|
*added_id = id;
|
||||||
@ -145,8 +146,8 @@ song_by_uri(const char *uri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_uri(struct playlist *playlist, const char *uri,
|
playlist_append_uri(struct playlist *playlist, struct player_control *pc,
|
||||||
unsigned *added_id)
|
const char *uri, unsigned *added_id)
|
||||||
{
|
{
|
||||||
struct song *song;
|
struct song *song;
|
||||||
|
|
||||||
@ -156,11 +157,12 @@ playlist_append_uri(struct playlist *playlist, const char *uri,
|
|||||||
if (song == NULL)
|
if (song == NULL)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_append_song(playlist, song, added_id);
|
return playlist_append_song(playlist, pc, song, added_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2)
|
playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned song1, unsigned song2)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
const struct song *queued;
|
||||||
|
|
||||||
@ -192,13 +194,14 @@ playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2)
|
|||||||
|
|
||||||
playlist_increment_version(playlist);
|
playlist_increment_version(playlist);
|
||||||
|
|
||||||
playlist_update_queued_song(playlist, queued);
|
playlist_update_queued_song(playlist, pc, queued);
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2)
|
playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned id1, unsigned id2)
|
||||||
{
|
{
|
||||||
int song1 = queue_id_to_position(&playlist->queue, id1);
|
int song1 = queue_id_to_position(&playlist->queue, id1);
|
||||||
int song2 = queue_id_to_position(&playlist->queue, id2);
|
int song2 = queue_id_to_position(&playlist->queue, id2);
|
||||||
@ -206,12 +209,12 @@ playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2)
|
|||||||
if (song1 < 0 || song2 < 0)
|
if (song1 < 0 || song2 < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_swap_songs(playlist, song1, song2);
|
return playlist_swap_songs(playlist, pc, song1, song2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
playlist_delete_internal(struct playlist *playlist, unsigned song,
|
playlist_delete_internal(struct playlist *playlist, struct player_control *pc,
|
||||||
const struct song **queued_p)
|
unsigned song, const struct song **queued_p)
|
||||||
{
|
{
|
||||||
unsigned songOrder;
|
unsigned songOrder;
|
||||||
|
|
||||||
@ -220,11 +223,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
|
|||||||
songOrder = queue_position_to_order(&playlist->queue, song);
|
songOrder = queue_position_to_order(&playlist->queue, song);
|
||||||
|
|
||||||
if (playlist->playing && playlist->current == (int)songOrder) {
|
if (playlist->playing && playlist->current == (int)songOrder) {
|
||||||
bool paused = pc_get_state() == PLAYER_STATE_PAUSE;
|
bool paused = pc_get_state(pc) == PLAYER_STATE_PAUSE;
|
||||||
|
|
||||||
/* the current song is going to be deleted: stop the player */
|
/* the current song is going to be deleted: stop the player */
|
||||||
|
|
||||||
pc_stop();
|
pc_stop(pc);
|
||||||
playlist->playing = false;
|
playlist->playing = false;
|
||||||
|
|
||||||
/* see which song is going to be played instead */
|
/* see which song is going to be played instead */
|
||||||
@ -236,11 +239,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
|
|||||||
|
|
||||||
if (playlist->current >= 0 && !paused)
|
if (playlist->current >= 0 && !paused)
|
||||||
/* play the song after the deleted one */
|
/* play the song after the deleted one */
|
||||||
playlist_play_order(playlist, playlist->current);
|
playlist_play_order(playlist, pc, playlist->current);
|
||||||
else
|
else
|
||||||
/* no songs left to play, stop playback
|
/* no songs left to play, stop playback
|
||||||
completely */
|
completely */
|
||||||
playlist_stop(playlist);
|
playlist_stop(playlist, pc);
|
||||||
|
|
||||||
*queued_p = NULL;
|
*queued_p = NULL;
|
||||||
} else if (playlist->current == (int)songOrder)
|
} else if (playlist->current == (int)songOrder)
|
||||||
@ -251,7 +254,7 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
|
|||||||
/* now do it: remove the song */
|
/* now do it: remove the song */
|
||||||
|
|
||||||
if (!song_in_database(queue_get(&playlist->queue, song)))
|
if (!song_in_database(queue_get(&playlist->queue, song)))
|
||||||
pc_song_deleted(queue_get(&playlist->queue, song));
|
pc_song_deleted(pc, queue_get(&playlist->queue, song));
|
||||||
|
|
||||||
queue_delete(&playlist->queue, song);
|
queue_delete(&playlist->queue, song);
|
||||||
|
|
||||||
@ -263,7 +266,8 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete(struct playlist *playlist, unsigned song)
|
playlist_delete(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned song)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
const struct song *queued;
|
||||||
|
|
||||||
@ -272,16 +276,17 @@ playlist_delete(struct playlist *playlist, unsigned song)
|
|||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
queued = playlist_get_queued_song(playlist);
|
||||||
|
|
||||||
playlist_delete_internal(playlist, song, &queued);
|
playlist_delete_internal(playlist, pc, song, &queued);
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
playlist_increment_version(playlist);
|
||||||
playlist_update_queued_song(playlist, queued);
|
playlist_update_queued_song(playlist, pc, queued);
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end)
|
playlist_delete_range(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned start, unsigned end)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
const struct song *queued;
|
||||||
|
|
||||||
@ -297,37 +302,39 @@ playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end)
|
|||||||
queued = playlist_get_queued_song(playlist);
|
queued = playlist_get_queued_song(playlist);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
playlist_delete_internal(playlist, --end, &queued);
|
playlist_delete_internal(playlist, pc, --end, &queued);
|
||||||
} while (end != start);
|
} while (end != start);
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
playlist_increment_version(playlist);
|
||||||
playlist_update_queued_song(playlist, queued);
|
playlist_update_queued_song(playlist, pc, queued);
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete_id(struct playlist *playlist, unsigned id)
|
playlist_delete_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned id)
|
||||||
{
|
{
|
||||||
int song = queue_id_to_position(&playlist->queue, id);
|
int song = queue_id_to_position(&playlist->queue, id);
|
||||||
if (song < 0)
|
if (song < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_delete(playlist, song);
|
return playlist_delete(playlist, pc, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_delete_song(struct playlist *playlist, const struct song *song)
|
playlist_delete_song(struct playlist *playlist, struct player_control *pc,
|
||||||
|
const struct song *song)
|
||||||
{
|
{
|
||||||
for (int i = queue_length(&playlist->queue) - 1; i >= 0; --i)
|
for (int i = queue_length(&playlist->queue) - 1; i >= 0; --i)
|
||||||
if (song == queue_get(&playlist->queue, i))
|
if (song == queue_get(&playlist->queue, i))
|
||||||
playlist_delete(playlist, i);
|
playlist_delete(playlist, pc, i);
|
||||||
|
|
||||||
pc_song_deleted(song);
|
pc_song_deleted(pc, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_move_range(struct playlist *playlist,
|
playlist_move_range(struct playlist *playlist, struct player_control *pc,
|
||||||
unsigned start, unsigned end, int to)
|
unsigned start, unsigned end, int to)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
const struct song *queued;
|
||||||
@ -382,23 +389,25 @@ playlist_move_range(struct playlist *playlist,
|
|||||||
|
|
||||||
playlist_increment_version(playlist);
|
playlist_increment_version(playlist);
|
||||||
|
|
||||||
playlist_update_queued_song(playlist, queued);
|
playlist_update_queued_song(playlist, pc, queued);
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_move_id(struct playlist *playlist, unsigned id1, int to)
|
playlist_move_id(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned id1, int to)
|
||||||
{
|
{
|
||||||
int song = queue_id_to_position(&playlist->queue, id1);
|
int song = queue_id_to_position(&playlist->queue, id1);
|
||||||
if (song < 0)
|
if (song < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_move_range(playlist, song, song+1, to);
|
return playlist_move_range(playlist, pc, song, song+1, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end)
|
playlist_shuffle(struct playlist *playlist, struct player_control *pc,
|
||||||
|
unsigned start, unsigned end)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
const struct song *queued;
|
||||||
|
|
||||||
@ -440,5 +449,5 @@ playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end)
|
|||||||
|
|
||||||
playlist_increment_version(playlist);
|
playlist_increment_version(playlist);
|
||||||
|
|
||||||
playlist_update_queued_song(playlist, queued);
|
playlist_update_queued_song(playlist, pc, queued);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
#include "playlist_state.h"
|
#include "playlist_state.h"
|
||||||
#include "event_pipe.h"
|
#include "event_pipe.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
struct playlist g_playlist;
|
struct playlist g_playlist;
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ playlist_tag_event(void)
|
|||||||
static void
|
static void
|
||||||
playlist_event(void)
|
playlist_event(void)
|
||||||
{
|
{
|
||||||
playlist_sync(&g_playlist);
|
playlist_sync(&g_playlist, global_player_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
|
|
||||||
|
struct player_control;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the song object which is currently queued. Returns none if
|
* Returns the song object which is currently queued. Returns none if
|
||||||
* there is none (yet?) or if MPD isn't playing.
|
* there is none (yet?) or if MPD isn't playing.
|
||||||
@ -44,9 +46,11 @@ playlist_get_queued_song(struct playlist *playlist);
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
playlist_update_queued_song(struct playlist *playlist,
|
playlist_update_queued_song(struct playlist *playlist,
|
||||||
|
struct player_control *pc,
|
||||||
const struct song *prev);
|
const struct song *prev);
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_play_order(struct playlist *playlist, int orderNum);
|
playlist_play_order(struct playlist *playlist, struct player_control *pc,
|
||||||
|
int orderNum);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,7 +27,8 @@
|
|||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_load_into_queue(const char *uri, struct playlist_provider *source,
|
playlist_load_into_queue(const char *uri, struct playlist_provider *source,
|
||||||
struct playlist *dest, bool secure)
|
struct playlist *dest, struct player_control *pc,
|
||||||
|
bool secure)
|
||||||
{
|
{
|
||||||
enum playlist_result result;
|
enum playlist_result result;
|
||||||
struct song *song;
|
struct song *song;
|
||||||
@ -38,7 +39,7 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source,
|
|||||||
if (song == NULL)
|
if (song == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result = playlist_append_song(dest, song, NULL);
|
result = playlist_append_song(dest, pc, song, NULL);
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS) {
|
if (result != PLAYLIST_RESULT_SUCCESS) {
|
||||||
if (!song_in_database(song))
|
if (!song_in_database(song))
|
||||||
song_free(song);
|
song_free(song);
|
||||||
@ -53,7 +54,9 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source,
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_open_into_queue(const char *uri, struct playlist *dest, bool secure)
|
playlist_open_into_queue(const char *uri,
|
||||||
|
struct playlist *dest, struct player_control *pc,
|
||||||
|
bool secure)
|
||||||
{
|
{
|
||||||
struct input_stream *is;
|
struct input_stream *is;
|
||||||
struct playlist_provider *playlist = playlist_open_any(uri, &is);
|
struct playlist_provider *playlist = playlist_open_any(uri, &is);
|
||||||
@ -61,7 +64,7 @@ playlist_open_into_queue(const char *uri, struct playlist *dest, bool secure)
|
|||||||
return PLAYLIST_RESULT_NO_SUCH_LIST;
|
return PLAYLIST_RESULT_NO_SUCH_LIST;
|
||||||
|
|
||||||
enum playlist_result result =
|
enum playlist_result result =
|
||||||
playlist_load_into_queue(uri, playlist, dest, secure);
|
playlist_load_into_queue(uri, playlist, dest, pc, secure);
|
||||||
playlist_plugin_close(playlist);
|
playlist_plugin_close(playlist);
|
||||||
|
|
||||||
if (is != NULL)
|
if (is != NULL)
|
||||||
|
@ -40,14 +40,17 @@ struct playlist;
|
|||||||
*/
|
*/
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_load_into_queue(const char *uri, struct playlist_provider *source,
|
playlist_load_into_queue(const char *uri, struct playlist_provider *source,
|
||||||
struct playlist *dest, bool secure);
|
struct playlist *dest, struct player_control *pc,
|
||||||
|
bool secure);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a playlist with a playlist plugin and append to the specified
|
* Opens a playlist with a playlist plugin and append to the specified
|
||||||
* play queue.
|
* play queue.
|
||||||
*/
|
*/
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_open_into_queue(const char *uri, struct playlist *dest, bool secure);
|
playlist_open_into_queue(const char *uri,
|
||||||
|
struct playlist *dest, struct player_control *pc,
|
||||||
|
bool secure);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -109,7 +109,8 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_load_spl(struct playlist *playlist, const char *name_utf8)
|
playlist_load_spl(struct playlist *playlist, struct player_control *pc,
|
||||||
|
const char *name_utf8)
|
||||||
{
|
{
|
||||||
GPtrArray *list;
|
GPtrArray *list;
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8)
|
|||||||
|
|
||||||
for (unsigned i = 0; i < list->len; ++i) {
|
for (unsigned i = 0; i < list->len; ++i) {
|
||||||
const char *temp = g_ptr_array_index(list, i);
|
const char *temp = g_ptr_array_index(list, i);
|
||||||
if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
|
if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
|
||||||
/* for windows compatibility, convert slashes */
|
/* for windows compatibility, convert slashes */
|
||||||
char *temp2 = g_strdup(temp);
|
char *temp2 = g_strdup(temp);
|
||||||
char *p = temp2;
|
char *p = temp2;
|
||||||
@ -128,7 +129,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8)
|
|||||||
*p = '/';
|
*p = '/';
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
|
if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
|
||||||
g_warning("can't add file \"%s\"", temp2);
|
g_warning("can't add file \"%s\"", temp2);
|
||||||
}
|
}
|
||||||
g_free(temp2);
|
g_free(temp2);
|
||||||
|
@ -49,6 +49,7 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist);
|
|||||||
* playlist.
|
* playlist.
|
||||||
*/
|
*/
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_load_spl(struct playlist *playlist, const char *name_utf8);
|
playlist_load_spl(struct playlist *playlist, struct player_control *pc,
|
||||||
|
const char *name_utf8);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -53,11 +53,12 @@
|
|||||||
#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
|
#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_state_save(FILE *fp, const struct playlist *playlist)
|
playlist_state_save(FILE *fp, const struct playlist *playlist,
|
||||||
|
struct player_control *pc)
|
||||||
{
|
{
|
||||||
struct player_status player_status;
|
struct player_status player_status;
|
||||||
|
|
||||||
pc_get_status(&player_status);
|
pc_get_status(pc, &player_status);
|
||||||
|
|
||||||
fputs(PLAYLIST_STATE_FILE_STATE, fp);
|
fputs(PLAYLIST_STATE_FILE_STATE, fp);
|
||||||
|
|
||||||
@ -89,10 +90,11 @@ playlist_state_save(FILE *fp, const struct playlist *playlist)
|
|||||||
fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n",
|
fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n",
|
||||||
playlist->queue.consume);
|
playlist->queue.consume);
|
||||||
fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n",
|
fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n",
|
||||||
(int)(pc_get_cross_fade()));
|
(int)(pc_get_cross_fade(pc)));
|
||||||
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", pc_get_mixramp_db());
|
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n",
|
||||||
|
pc_get_mixramp_db(pc));
|
||||||
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n",
|
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n",
|
||||||
pc_get_mixramp_delay());
|
pc_get_mixramp_delay(pc));
|
||||||
fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp);
|
fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp);
|
||||||
queue_save(fp, &playlist->queue);
|
queue_save(fp, &playlist->queue);
|
||||||
fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp);
|
fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp);
|
||||||
@ -123,7 +125,7 @@ playlist_state_load(FILE *fp, GString *buffer, struct playlist *playlist)
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
||||||
struct playlist *playlist)
|
struct playlist *playlist, struct player_control *pc)
|
||||||
{
|
{
|
||||||
int current = -1;
|
int current = -1;
|
||||||
int seek_time = 0;
|
int seek_time = 0;
|
||||||
@ -148,16 +150,16 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
|||||||
if (strcmp
|
if (strcmp
|
||||||
(&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
|
(&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
|
||||||
"1") == 0) {
|
"1") == 0) {
|
||||||
playlist_set_repeat(playlist, true);
|
playlist_set_repeat(playlist, pc, true);
|
||||||
} else
|
} else
|
||||||
playlist_set_repeat(playlist, false);
|
playlist_set_repeat(playlist, pc, false);
|
||||||
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) {
|
||||||
if (strcmp
|
if (strcmp
|
||||||
(&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]),
|
(&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]),
|
||||||
"1") == 0) {
|
"1") == 0) {
|
||||||
playlist_set_single(playlist, true);
|
playlist_set_single(playlist, pc, true);
|
||||||
} else
|
} else
|
||||||
playlist_set_single(playlist, false);
|
playlist_set_single(playlist, pc, false);
|
||||||
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) {
|
||||||
if (strcmp
|
if (strcmp
|
||||||
(&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]),
|
(&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]),
|
||||||
@ -166,11 +168,14 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
|||||||
} else
|
} else
|
||||||
playlist_set_consume(playlist, false);
|
playlist_set_consume(playlist, false);
|
||||||
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) {
|
||||||
pc_set_cross_fade(atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE)));
|
pc_set_cross_fade(pc,
|
||||||
|
atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE)));
|
||||||
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB)) {
|
||||||
pc_set_mixramp_db(atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB)));
|
pc_set_mixramp_db(pc,
|
||||||
|
atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB)));
|
||||||
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) {
|
||||||
pc_set_mixramp_delay(atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY)));
|
pc_set_mixramp_delay(pc,
|
||||||
|
atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY)));
|
||||||
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_RANDOM)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_RANDOM)) {
|
||||||
random_mode =
|
random_mode =
|
||||||
strcmp(line + strlen(PLAYLIST_STATE_FILE_RANDOM),
|
strcmp(line + strlen(PLAYLIST_STATE_FILE_RANDOM),
|
||||||
@ -185,7 +190,7 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_set_random(playlist, random_mode);
|
playlist_set_random(playlist, pc, random_mode);
|
||||||
|
|
||||||
if (!queue_is_empty(&playlist->queue)) {
|
if (!queue_is_empty(&playlist->queue)) {
|
||||||
if (!queue_valid_position(&playlist->queue, current))
|
if (!queue_valid_position(&playlist->queue, current))
|
||||||
@ -195,28 +200,29 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
|||||||
called here, after the audio output states were
|
called here, after the audio output states were
|
||||||
restored, before playback begins */
|
restored, before playback begins */
|
||||||
if (state != PLAYER_STATE_STOP)
|
if (state != PLAYER_STATE_STOP)
|
||||||
pc_update_audio();
|
pc_update_audio(pc);
|
||||||
|
|
||||||
if (state == PLAYER_STATE_STOP /* && config_option */)
|
if (state == PLAYER_STATE_STOP /* && config_option */)
|
||||||
playlist->current = current;
|
playlist->current = current;
|
||||||
else if (seek_time == 0)
|
else if (seek_time == 0)
|
||||||
playlist_play(playlist, current);
|
playlist_play(playlist, pc, current);
|
||||||
else
|
else
|
||||||
playlist_seek_song(playlist, current, seek_time);
|
playlist_seek_song(playlist, pc, current, seek_time);
|
||||||
|
|
||||||
if (state == PLAYER_STATE_PAUSE)
|
if (state == PLAYER_STATE_PAUSE)
|
||||||
pc_pause();
|
pc_pause(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
playlist_state_get_hash(const struct playlist *playlist)
|
playlist_state_get_hash(const struct playlist *playlist,
|
||||||
|
struct player_control *pc)
|
||||||
{
|
{
|
||||||
struct player_status player_status;
|
struct player_status player_status;
|
||||||
|
|
||||||
pc_get_status(&player_status);
|
pc_get_status(pc, &player_status);
|
||||||
|
|
||||||
return playlist->queue.version ^
|
return playlist->queue.version ^
|
||||||
(player_status.state != PLAYER_STATE_STOP
|
(player_status.state != PLAYER_STATE_STOP
|
||||||
@ -226,7 +232,7 @@ playlist_state_get_hash(const struct playlist *playlist)
|
|||||||
? (queue_order_to_position(&playlist->queue,
|
? (queue_order_to_position(&playlist->queue,
|
||||||
playlist->current) << 16)
|
playlist->current) << 16)
|
||||||
: 0) ^
|
: 0) ^
|
||||||
((int)pc_get_cross_fade() << 20) ^
|
((int)pc_get_cross_fade(pc) << 20) ^
|
||||||
(player_status.state << 24) ^
|
(player_status.state << 24) ^
|
||||||
(playlist->queue.random << 27) ^
|
(playlist->queue.random << 27) ^
|
||||||
(playlist->queue.repeat << 28) ^
|
(playlist->queue.repeat << 28) ^
|
||||||
|
@ -30,13 +30,15 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
struct playlist;
|
struct playlist;
|
||||||
|
struct player_control;
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_state_save(FILE *fp, const struct playlist *playlist);
|
playlist_state_save(FILE *fp, const struct playlist *playlist,
|
||||||
|
struct player_control *pc);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
||||||
struct playlist *playlist);
|
struct playlist *playlist, struct player_control *pc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a hash number for the current state of the playlist and
|
* Generates a hash number for the current state of the playlist and
|
||||||
@ -45,6 +47,7 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
|
|||||||
* be saved.
|
* be saved.
|
||||||
*/
|
*/
|
||||||
unsigned
|
unsigned
|
||||||
playlist_state_get_hash(const struct playlist *playlist);
|
playlist_state_get_hash(const struct playlist *playlist,
|
||||||
|
struct player_control *pc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,7 +47,7 @@ static unsigned prev_volume_version, prev_output_version,
|
|||||||
prev_playlist_version;
|
prev_playlist_version;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
state_file_write(void)
|
state_file_write(struct player_control *pc)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
@ -64,17 +64,17 @@ state_file_write(void)
|
|||||||
|
|
||||||
save_sw_volume_state(fp);
|
save_sw_volume_state(fp);
|
||||||
audio_output_state_save(fp);
|
audio_output_state_save(fp);
|
||||||
playlist_state_save(fp, &g_playlist);
|
playlist_state_save(fp, &g_playlist, pc);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
prev_volume_version = sw_volume_state_get_hash();
|
prev_volume_version = sw_volume_state_get_hash();
|
||||||
prev_output_version = audio_output_state_get_version();
|
prev_output_version = audio_output_state_get_version();
|
||||||
prev_playlist_version = playlist_state_get_hash(&g_playlist);
|
prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
state_file_read(void)
|
state_file_read(struct player_control *pc)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
bool success;
|
bool success;
|
||||||
@ -95,7 +95,8 @@ state_file_read(void)
|
|||||||
while ((line = read_text_line(fp, buffer)) != NULL) {
|
while ((line = read_text_line(fp, buffer)) != NULL) {
|
||||||
success = read_sw_volume_state(line) ||
|
success = read_sw_volume_state(line) ||
|
||||||
audio_output_state_read(line) ||
|
audio_output_state_read(line) ||
|
||||||
playlist_state_restore(line, fp, buffer, &g_playlist);
|
playlist_state_restore(line, fp, buffer,
|
||||||
|
&g_playlist, pc);
|
||||||
if (!success)
|
if (!success)
|
||||||
g_warning("Unrecognized line in state file: %s", line);
|
g_warning("Unrecognized line in state file: %s", line);
|
||||||
}
|
}
|
||||||
@ -104,7 +105,7 @@ state_file_read(void)
|
|||||||
|
|
||||||
prev_volume_version = sw_volume_state_get_hash();
|
prev_volume_version = sw_volume_state_get_hash();
|
||||||
prev_output_version = audio_output_state_get_version();
|
prev_output_version = audio_output_state_get_version();
|
||||||
prev_playlist_version = playlist_state_get_hash(&g_playlist);
|
prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
|
||||||
|
|
||||||
|
|
||||||
g_string_free(buffer, true);
|
g_string_free(buffer, true);
|
||||||
@ -115,21 +116,23 @@ state_file_read(void)
|
|||||||
* saves the state file.
|
* saves the state file.
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
timer_save_state_file(G_GNUC_UNUSED gpointer data)
|
timer_save_state_file(gpointer data)
|
||||||
{
|
{
|
||||||
|
struct player_control *pc = data;
|
||||||
|
|
||||||
if (prev_volume_version == sw_volume_state_get_hash() &&
|
if (prev_volume_version == sw_volume_state_get_hash() &&
|
||||||
prev_output_version == audio_output_state_get_version() &&
|
prev_output_version == audio_output_state_get_version() &&
|
||||||
prev_playlist_version == playlist_state_get_hash(&g_playlist))
|
prev_playlist_version == playlist_state_get_hash(&g_playlist, pc))
|
||||||
/* nothing has changed - don't save the state file,
|
/* nothing has changed - don't save the state file,
|
||||||
don't spin up the hard disk */
|
don't spin up the hard disk */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
state_file_write();
|
state_file_write(pc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
state_file_init(const char *path)
|
state_file_init(const char *path, struct player_control *pc)
|
||||||
{
|
{
|
||||||
assert(state_file_path == NULL);
|
assert(state_file_path == NULL);
|
||||||
|
|
||||||
@ -137,15 +140,15 @@ state_file_init(const char *path)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
state_file_path = g_strdup(path);
|
state_file_path = g_strdup(path);
|
||||||
state_file_read();
|
state_file_read(pc);
|
||||||
|
|
||||||
save_state_source_id = g_timeout_add_seconds(5 * 60,
|
save_state_source_id = g_timeout_add_seconds(5 * 60,
|
||||||
timer_save_state_file,
|
timer_save_state_file,
|
||||||
NULL);
|
pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
state_file_finish(void)
|
state_file_finish(struct player_control *pc)
|
||||||
{
|
{
|
||||||
if (state_file_path == NULL)
|
if (state_file_path == NULL)
|
||||||
/* no state file configured, no cleanup required */
|
/* no state file configured, no cleanup required */
|
||||||
@ -154,7 +157,7 @@ state_file_finish(void)
|
|||||||
if (save_state_source_id != 0)
|
if (save_state_source_id != 0)
|
||||||
g_source_remove(save_state_source_id);
|
g_source_remove(save_state_source_id);
|
||||||
|
|
||||||
state_file_write();
|
state_file_write(pc);
|
||||||
|
|
||||||
g_free(state_file_path);
|
g_free(state_file_path);
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,13 @@
|
|||||||
#ifndef MPD_STATE_FILE_H
|
#ifndef MPD_STATE_FILE_H
|
||||||
#define MPD_STATE_FILE_H
|
#define MPD_STATE_FILE_H
|
||||||
|
|
||||||
void
|
struct player_control;
|
||||||
state_file_init(const char *path);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
state_file_finish(void);
|
state_file_init(const char *path, struct player_control *pc);
|
||||||
|
|
||||||
|
void
|
||||||
|
state_file_finish(struct player_control *pc);
|
||||||
|
|
||||||
void write_state_file(void);
|
void write_state_file(void);
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "player_control.h"
|
#include "player_control.h"
|
||||||
#include "strset.h"
|
#include "strset.h"
|
||||||
|
#include "client_internal.h"
|
||||||
|
|
||||||
struct stats stats;
|
struct stats stats;
|
||||||
|
|
||||||
@ -114,7 +115,7 @@ int stats_print(struct client *client)
|
|||||||
stats.album_count,
|
stats.album_count,
|
||||||
stats.song_count,
|
stats.song_count,
|
||||||
(long)g_timer_elapsed(stats.timer, NULL),
|
(long)g_timer_elapsed(stats.timer, NULL),
|
||||||
(long)(pc_get_total_play_time() + 0.5),
|
(long)(pc_get_total_play_time(client->player_control) + 0.5),
|
||||||
stats.song_duration,
|
stats.song_duration,
|
||||||
db_get_mtime());
|
db_get_mtime());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "event_pipe.h"
|
#include "event_pipe.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
#ifdef ENABLE_SQLITE
|
#ifdef ENABLE_SQLITE
|
||||||
#include "sticker.h"
|
#include "sticker.h"
|
||||||
@ -58,7 +59,7 @@ song_remove_event(void)
|
|||||||
sticker_song_delete(removed_song);
|
sticker_song_delete(removed_song);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
playlist_delete_song(&g_playlist, removed_song);
|
playlist_delete_song(&g_playlist, global_player_control, removed_song);
|
||||||
removed_song = NULL;
|
removed_song = NULL;
|
||||||
|
|
||||||
notify_signal(&remove_notify);
|
notify_signal(&remove_notify);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "event_pipe.h"
|
#include "event_pipe.h"
|
||||||
#include "idle.h"
|
#include "idle.h"
|
||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
|
#include "player_control.h"
|
||||||
#include "stdbin.h"
|
#include "stdbin.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
@ -104,7 +105,9 @@ load_audio_output(struct audio_output *ao, const char *name)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = audio_output_init(ao, param, &error);
|
static struct player_control dummy_player_control;
|
||||||
|
|
||||||
|
success = audio_output_init(ao, param, &dummy_player_control, &error);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
g_printerr("%s\n", error->message);
|
g_printerr("%s\n", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
Loading…
Reference in New Issue
Block a user