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/path.c \
src/Mapper.cxx src/Mapper.hxx \ src/Mapper.cxx src/Mapper.hxx \
src/page.c \ src/page.c \
src/Partition.hxx \
src/Permission.cxx src/Permission.hxx \ src/Permission.cxx src/Permission.hxx \
src/PlayerThread.cxx src/PlayerThread.hxx \ src/PlayerThread.cxx src/PlayerThread.hxx \
src/PlayerControl.cxx src/PlayerControl.hxx \ src/PlayerControl.cxx src/PlayerControl.hxx \

View File

@ -20,7 +20,7 @@
#include "config.h" #include "config.h"
#include "Listen.hxx" #include "Listen.hxx"
#include "Main.hxx" #include "Main.hxx"
#include "Playlist.hxx" #include "Partition.hxx"
#include "Client.hxx" #include "Client.hxx"
extern "C" { extern "C" {
@ -47,7 +47,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(g_playlist, global_player_control, client_new(global_partition->playlist, &global_partition->pc,
fd, address, address_length, uid); fd, address, address_length, uid);
} }

View File

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

View File

@ -28,7 +28,7 @@ extern GMainLoop *main_loop;
extern GCond *main_cond; extern GCond *main_cond;
extern struct player_control *global_player_control; extern struct Partition *global_partition;
/** /**
* A entry point for application. * 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; int queued;
}; };
/** the global playlist object */
extern struct playlist g_playlist;
void void
playlist_global_init(unsigned max_length); playlist_global_init();
void
playlist_global_finish(void);
void void
playlist_init(struct playlist *playlist, unsigned max_length); playlist_init(struct playlist *playlist, unsigned max_length);

View File

@ -25,36 +25,28 @@
#include "config.h" #include "config.h"
#include "Playlist.hxx" #include "Playlist.hxx"
#include "Main.hxx" #include "Main.hxx"
#include "Partition.hxx"
extern "C" { extern "C" {
#include "event_pipe.h" #include "event_pipe.h"
} }
struct playlist g_playlist;
static void static void
playlist_tag_event(void) playlist_tag_event(void)
{ {
playlist_tag_changed(&g_playlist); playlist_tag_changed(&global_partition->playlist);
} }
static void static void
playlist_event(void) playlist_event(void)
{ {
playlist_sync(&g_playlist, global_player_control); playlist_sync(&global_partition->playlist,
&global_partition->pc);
} }
void 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_TAG, playlist_tag_event);
event_pipe_register(PIPE_EVENT_PLAYLIST, playlist_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 "config.h"
#include "StateFile.hxx" #include "StateFile.hxx"
#include "OutputState.hxx" #include "OutputState.hxx"
#include "Playlist.hxx"
#include "PlaylistState.hxx" #include "PlaylistState.hxx"
#include "TextFile.hxx" #include "TextFile.hxx"
#include "Partition.hxx"
extern "C" { extern "C" {
#include "volume.h" #include "volume.h"
@ -49,7 +49,7 @@ static unsigned prev_volume_version, prev_output_version,
prev_playlist_version; prev_playlist_version;
static void static void
state_file_write(struct player_control *pc) state_file_write(Partition &partition)
{ {
FILE *fp; FILE *fp;
@ -66,17 +66,18 @@ state_file_write(struct player_control *pc)
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, pc); playlist_state_save(fp, &partition.playlist, &partition.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, pc); prev_playlist_version = playlist_state_get_hash(&partition.playlist,
&partition.pc);
} }
static void static void
state_file_read(struct player_control *pc) state_file_read(Partition &partition)
{ {
bool success; bool success;
@ -95,14 +96,16 @@ state_file_read(struct player_control *pc)
while ((line = file.ReadLine()) != NULL) { while ((line = file.ReadLine()) != 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, file, &g_playlist, pc); playlist_state_restore(line, file, &partition.playlist,
&partition.pc);
if (!success) if (!success)
g_warning("Unrecognized line in state file: %s", line); g_warning("Unrecognized line in state file: %s", line);
} }
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, 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 static gboolean
timer_save_state_file(gpointer data) 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() && 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, pc)) prev_playlist_version == playlist_state_get_hash(&partition.playlist,
&partition.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(pc); state_file_write(partition);
return true; return true;
} }
void void
state_file_init(const char *path, struct player_control *pc) state_file_init(const char *path, Partition &partition)
{ {
assert(state_file_path == NULL); assert(state_file_path == NULL);
@ -134,15 +138,15 @@ state_file_init(const char *path, struct player_control *pc)
return; return;
state_file_path = g_strdup(path); state_file_path = g_strdup(path);
state_file_read(pc); state_file_read(partition);
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,
pc); &partition);
} }
void void
state_file_finish(struct player_control *pc) state_file_finish(Partition &partition)
{ {
if (state_file_path == NULL) if (state_file_path == NULL)
/* no state file configured, no cleanup required */ /* no state file configured, no cleanup required */
@ -151,7 +155,7 @@ state_file_finish(struct player_control *pc)
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(pc); state_file_write(partition);
g_free(state_file_path); g_free(state_file_path);
} }

View File

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

View File

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

View File

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