Partition: new class, container for Playlist and PlayerControl

This is the beginning of multi-player support.  There will be support
for multiple Partition objects in one MPD process.
This commit is contained in:
Max Kellermann 2013-01-04 22:42:05 +01:00
parent 1a8ef3cdab
commit d536944beb
11 changed files with 103 additions and 60 deletions

View File

@ -262,6 +262,7 @@ src_mpd_SOURCES = \
src/path.c \
src/Mapper.cxx src/Mapper.hxx \
src/page.c \
src/Partition.hxx \
src/Permission.cxx src/Permission.hxx \
src/PlayerThread.cxx src/PlayerThread.hxx \
src/PlayerControl.cxx src/PlayerControl.hxx \

View File

@ -20,7 +20,7 @@
#include "config.h"
#include "Listen.hxx"
#include "Main.hxx"
#include "Playlist.hxx"
#include "Partition.hxx"
#include "Client.hxx"
extern "C" {
@ -47,7 +47,7 @@ static void
listen_callback(int fd, const struct sockaddr *address,
size_t address_length, int uid, G_GNUC_UNUSED void *ctx)
{
client_new(g_playlist, global_player_control,
client_new(global_partition->playlist, &global_partition->pc,
fd, address, address_length, uid);
}

View File

@ -20,9 +20,7 @@
#include "config.h"
#include "Main.hxx"
#include "CommandLine.hxx"
#include "Playlist.hxx"
#include "PlaylistFile.hxx"
#include "PlayerControl.hxx"
#include "UpdateGlue.hxx"
#include "MusicChunk.hxx"
#include "StateFile.hxx"
@ -35,6 +33,7 @@
#include "ClientIdle.hxx"
#include "Client.hxx"
#include "AllCommands.hxx"
#include "Partition.hxx"
extern "C" {
#include "daemon.h"
@ -100,7 +99,7 @@ GMainLoop *main_loop;
GCond *main_cond;
struct player_control *global_player_control;
Partition *global_partition;
static bool
glue_daemonize_init(const struct options *options, GError **error_r)
@ -231,7 +230,7 @@ glue_state_file_init(GError **error_r)
return false;
}
state_file_init(path, global_player_control);
state_file_init(path, *global_partition);
g_free(path);
return true;
@ -306,8 +305,13 @@ initialize_decoder_and_player(void)
if (buffered_before_play > buffered_chunks)
buffered_before_play = buffered_chunks;
global_player_control = new player_control(buffered_chunks,
buffered_before_play);
const unsigned max_length =
config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
DEFAULT_PLAYLIST_MAX_LENGTH);
global_partition = new Partition(max_length,
buffered_chunks,
buffered_before_play);
}
/**
@ -414,8 +418,7 @@ int mpd_main(int argc, char *argv[])
}
initPermissions();
playlist_global_init(config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
DEFAULT_PLAYLIST_MAX_LENGTH));
playlist_global_init();
spl_global_init();
#ifdef ENABLE_ARCHIVE
archive_plugin_init_all();
@ -438,7 +441,7 @@ int mpd_main(int argc, char *argv[])
initialize_decoder_and_player();
volume_init();
initAudioConfig();
audio_output_all_init(global_player_control);
audio_output_all_init(&global_partition->pc);
client_manager_init();
replay_gain_global_init();
@ -464,7 +467,7 @@ int mpd_main(int argc, char *argv[])
initZeroconf();
player_create(global_player_control);
player_create(&global_partition->pc);
if (create_db) {
/* the database failed to load: recreate the
@ -480,7 +483,7 @@ int mpd_main(int argc, char *argv[])
return EXIT_FAILURE;
}
audio_output_all_set_replay_gain_mode(replay_gain_get_real_mode(g_playlist.queue.random));
audio_output_all_set_replay_gain_mode(replay_gain_get_real_mode(global_partition->playlist.queue.random));
success = config_get_bool(CONF_AUTO_UPDATE, false);
#ifdef ENABLE_INOTIFY
@ -496,7 +499,7 @@ int mpd_main(int argc, char *argv[])
/* enable all audio outputs (if not already done by
playlist_state_restore() */
pc_update_audio(global_player_control);
pc_update_audio(&global_partition->pc);
#ifdef WIN32
win32_app_started();
@ -517,12 +520,11 @@ int mpd_main(int argc, char *argv[])
mpd_inotify_finish();
#endif
state_file_finish(global_player_control);
pc_kill(global_player_control);
state_file_finish(*global_partition);
pc_kill(&global_partition->pc);
finishZeroconf();
client_manager_deinit();
listen_global_finish();
playlist_global_finish();
start = clock();
DatabaseGlobalDeinit();
@ -542,7 +544,7 @@ int mpd_main(int argc, char *argv[])
volume_finish();
mapper_finish();
path_global_finish();
delete global_player_control;
delete global_partition;
command_finish();
update_global_finish();
decoder_plugin_deinit_all();

View File

@ -28,7 +28,7 @@ extern GMainLoop *main_loop;
extern GCond *main_cond;
extern struct player_control *global_player_control;
extern struct Partition *global_partition;
/**
* A entry point for application.

47
src/Partition.hxx Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_PARTITION_HXX
#define MPD_PARTITION_HXX
#include "Playlist.hxx"
#include "PlayerControl.hxx"
/**
* A partition of the Music Player Daemon. It is a separate unit with
* a playlist, a player, outputs etc.
*/
struct Partition {
struct playlist playlist;
player_control pc;
Partition(unsigned max_length,
unsigned buffer_chunks,
unsigned buffered_before_play)
:pc(buffer_chunks, buffered_before_play) {
playlist_init(&playlist, max_length);
}
~Partition() {
playlist_finish(&playlist);
}
};
#endif

View File

@ -70,14 +70,8 @@ struct playlist {
int queued;
};
/** the global playlist object */
extern struct playlist g_playlist;
void
playlist_global_init(unsigned max_length);
void
playlist_global_finish(void);
playlist_global_init();
void
playlist_init(struct playlist *playlist, unsigned max_length);

View File

@ -25,36 +25,28 @@
#include "config.h"
#include "Playlist.hxx"
#include "Main.hxx"
#include "Partition.hxx"
extern "C" {
#include "event_pipe.h"
}
struct playlist g_playlist;
static void
playlist_tag_event(void)
{
playlist_tag_changed(&g_playlist);
playlist_tag_changed(&global_partition->playlist);
}
static void
playlist_event(void)
{
playlist_sync(&g_playlist, global_player_control);
playlist_sync(&global_partition->playlist,
&global_partition->pc);
}
void
playlist_global_init(unsigned max_length)
playlist_global_init()
{
playlist_init(&g_playlist, max_length);
event_pipe_register(PIPE_EVENT_TAG, playlist_tag_event);
event_pipe_register(PIPE_EVENT_PLAYLIST, playlist_event);
}
void
playlist_global_finish(void)
{
playlist_finish(&g_playlist);
}

View File

@ -20,9 +20,9 @@
#include "config.h"
#include "StateFile.hxx"
#include "OutputState.hxx"
#include "Playlist.hxx"
#include "PlaylistState.hxx"
#include "TextFile.hxx"
#include "Partition.hxx"
extern "C" {
#include "volume.h"
@ -49,7 +49,7 @@ static unsigned prev_volume_version, prev_output_version,
prev_playlist_version;
static void
state_file_write(struct player_control *pc)
state_file_write(Partition &partition)
{
FILE *fp;
@ -66,17 +66,18 @@ state_file_write(struct player_control *pc)
save_sw_volume_state(fp);
audio_output_state_save(fp);
playlist_state_save(fp, &g_playlist, pc);
playlist_state_save(fp, &partition.playlist, &partition.pc);
fclose(fp);
prev_volume_version = sw_volume_state_get_hash();
prev_output_version = audio_output_state_get_version();
prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
prev_playlist_version = playlist_state_get_hash(&partition.playlist,
&partition.pc);
}
static void
state_file_read(struct player_control *pc)
state_file_read(Partition &partition)
{
bool success;
@ -95,14 +96,16 @@ state_file_read(struct player_control *pc)
while ((line = file.ReadLine()) != NULL) {
success = read_sw_volume_state(line) ||
audio_output_state_read(line) ||
playlist_state_restore(line, file, &g_playlist, pc);
playlist_state_restore(line, file, &partition.playlist,
&partition.pc);
if (!success)
g_warning("Unrecognized line in state file: %s", line);
}
prev_volume_version = sw_volume_state_get_hash();
prev_output_version = audio_output_state_get_version();
prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
prev_playlist_version = playlist_state_get_hash(&partition.playlist,
&partition.pc);
}
/**
@ -112,21 +115,22 @@ state_file_read(struct player_control *pc)
static gboolean
timer_save_state_file(gpointer data)
{
struct player_control *pc = (struct player_control *)data;
Partition &partition = *(Partition *)data;
if (prev_volume_version == sw_volume_state_get_hash() &&
prev_output_version == audio_output_state_get_version() &&
prev_playlist_version == playlist_state_get_hash(&g_playlist, pc))
prev_playlist_version == playlist_state_get_hash(&partition.playlist,
&partition.pc))
/* nothing has changed - don't save the state file,
don't spin up the hard disk */
return true;
state_file_write(pc);
state_file_write(partition);
return true;
}
void
state_file_init(const char *path, struct player_control *pc)
state_file_init(const char *path, Partition &partition)
{
assert(state_file_path == NULL);
@ -134,15 +138,15 @@ state_file_init(const char *path, struct player_control *pc)
return;
state_file_path = g_strdup(path);
state_file_read(pc);
state_file_read(partition);
save_state_source_id = g_timeout_add_seconds(5 * 60,
timer_save_state_file,
pc);
&partition);
}
void
state_file_finish(struct player_control *pc)
state_file_finish(Partition &partition)
{
if (state_file_path == NULL)
/* no state file configured, no cleanup required */
@ -151,7 +155,7 @@ state_file_finish(struct player_control *pc)
if (save_state_source_id != 0)
g_source_remove(save_state_source_id);
state_file_write(pc);
state_file_write(partition);
g_free(state_file_path);
}

View File

@ -20,13 +20,13 @@
#ifndef MPD_STATE_FILE_HXX
#define MPD_STATE_FILE_HXX
struct player_control;
struct Partition;
void
state_file_init(const char *path, struct player_control *pc);
state_file_init(const char *path, Partition &partition);
void
state_file_finish(struct player_control *pc);
state_file_finish(Partition &partition);
void write_state_file(void);

View File

@ -24,7 +24,6 @@
#include "UpdateRemove.hxx"
#include "Mapper.hxx"
#include "DatabaseSimple.hxx"
#include "Playlist.hxx"
extern "C" {
#include "event_pipe.h"
@ -33,6 +32,7 @@ extern "C" {
}
#include "Main.hxx"
#include "Partition.hxx"
#include "mpd_error.h"
#include <glib.h>
@ -155,7 +155,7 @@ static void update_finished_event(void)
if (modified) {
/* send "idle" events */
playlist_increment_version_all(&g_playlist);
playlist_increment_version_all(&global_partition->playlist);
idle_add(IDLE_DATABASE);
}

View File

@ -20,6 +20,7 @@
#include "config.h" /* must be first for large file support */
#include "UpdateRemove.hxx"
#include "Playlist.hxx"
#include "Partition.hxx"
extern "C" {
#include "event_pipe.h"
@ -63,7 +64,9 @@ song_remove_event(void)
sticker_song_delete(removed_song);
#endif
playlist_delete_song(&g_playlist, global_player_control, removed_song);
playlist_delete_song(&global_partition->playlist,
&global_partition->pc,
removed_song);
/* clear "removed_song" and send signal to update thread */
g_mutex_lock(remove_mutex);