~ubuntu-branches/ubuntu/utopic/mpd/utopic-proposed

« back to all changes in this revision

Viewing changes to src/PlaylistControl.cxx

  • Committer: Package Import Robot
  • Author(s): Steve Kowalik
  • Date: 2013-11-12 18:17:40 UTC
  • mfrom: (2.2.36 sid)
  • Revision ID: package-import@ubuntu.com-20131112181740-72aa4zihehoobedp
Tags: 0.18.3-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - Add libmp3lame-dev to Build-Depends, and enable LAME.
  - Read the user for the daemon from the config file in the init script.
  - Move avahi-daemon from Suggests to Recommends.
  - Added apport hook to include user configuration file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2003-2013 The Music Player Daemon Project
 
3
 * http://www.musicpd.org
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License along
 
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
18
 */
 
19
 
 
20
/*
 
21
 * Functions for controlling playback on the playlist level.
 
22
 *
 
23
 */
 
24
 
 
25
#include "config.h"
 
26
#include "Playlist.hxx"
 
27
#include "PlaylistError.hxx"
 
28
#include "PlayerControl.hxx"
 
29
#include "Song.hxx"
 
30
#include "Log.hxx"
 
31
 
 
32
void
 
33
playlist::Stop(PlayerControl &pc)
 
34
{
 
35
        if (!playing)
 
36
                return;
 
37
 
 
38
        assert(current >= 0);
 
39
 
 
40
        FormatDebug(playlist_domain, "stop");
 
41
        pc.Stop();
 
42
        queued = -1;
 
43
        playing = false;
 
44
 
 
45
        if (queue.random) {
 
46
                /* shuffle the playlist, so the next playback will
 
47
                   result in a new random order */
 
48
 
 
49
                unsigned current_position = queue.OrderToPosition(current);
 
50
 
 
51
                queue.ShuffleOrder();
 
52
 
 
53
                /* make sure that "current" stays valid, and the next
 
54
                   "play" command plays the same song again */
 
55
                current = queue.PositionToOrder(current_position);
 
56
        }
 
57
}
 
58
 
 
59
PlaylistResult
 
60
playlist::PlayPosition(PlayerControl &pc, int song)
 
61
{
 
62
        pc.ClearError();
 
63
 
 
64
        unsigned i = song;
 
65
        if (song == -1) {
 
66
                /* play any song ("current" song, or the first song */
 
67
 
 
68
                if (queue.IsEmpty())
 
69
                        return PlaylistResult::SUCCESS;
 
70
 
 
71
                if (playing) {
 
72
                        /* already playing: unpause playback, just in
 
73
                           case it was paused, and return */
 
74
                        pc.SetPause(false);
 
75
                        return PlaylistResult::SUCCESS;
 
76
                }
 
77
 
 
78
                /* select a song: "current" song, or the first one */
 
79
                i = current >= 0
 
80
                        ? current
 
81
                        : 0;
 
82
        } else if (!queue.IsValidPosition(song))
 
83
                return PlaylistResult::BAD_RANGE;
 
84
 
 
85
        if (queue.random) {
 
86
                if (song >= 0)
 
87
                        /* "i" is currently the song position (which
 
88
                           would be equal to the order number in
 
89
                           no-random mode); convert it to a order
 
90
                           number, because random mode is enabled */
 
91
                        i = queue.PositionToOrder(song);
 
92
 
 
93
                if (!playing)
 
94
                        current = 0;
 
95
 
 
96
                /* swap the new song with the previous "current" one,
 
97
                   so playback continues as planned */
 
98
                queue.SwapOrders(i, current);
 
99
                i = current;
 
100
        }
 
101
 
 
102
        stop_on_error = false;
 
103
        error_count = 0;
 
104
 
 
105
        PlayOrder(pc, i);
 
106
        return PlaylistResult::SUCCESS;
 
107
}
 
108
 
 
109
PlaylistResult
 
110
playlist::PlayId(PlayerControl &pc, int id)
 
111
{
 
112
        if (id == -1)
 
113
                return PlayPosition(pc, id);
 
114
 
 
115
        int song = queue.IdToPosition(id);
 
116
        if (song < 0)
 
117
                return PlaylistResult::NO_SUCH_SONG;
 
118
 
 
119
        return PlayPosition(pc, song);
 
120
}
 
121
 
 
122
void
 
123
playlist::PlayNext(PlayerControl &pc)
 
124
{
 
125
        if (!playing)
 
126
                return;
 
127
 
 
128
        assert(!queue.IsEmpty());
 
129
        assert(queue.IsValidOrder(current));
 
130
 
 
131
        const int old_current = current;
 
132
        stop_on_error = false;
 
133
 
 
134
        /* determine the next song from the queue's order list */
 
135
 
 
136
        const int next_order = queue.GetNextOrder(current);
 
137
        if (next_order < 0) {
 
138
                /* no song after this one: stop playback */
 
139
                Stop(pc);
 
140
 
 
141
                /* reset "current song" */
 
142
                current = -1;
 
143
        }
 
144
        else
 
145
        {
 
146
                if (next_order == 0 && queue.random) {
 
147
                        /* The queue told us that the next song is the first
 
148
                           song.  This means we are in repeat mode.  Shuffle
 
149
                           the queue order, so this time, the user hears the
 
150
                           songs in a different than before */
 
151
                        assert(queue.repeat);
 
152
 
 
153
                        queue.ShuffleOrder();
 
154
 
 
155
                        /* note that current and queued are
 
156
                           now invalid, but playlist_play_order() will
 
157
                           discard them anyway */
 
158
                }
 
159
 
 
160
                PlayOrder(pc, next_order);
 
161
        }
 
162
 
 
163
        /* Consume mode removes each played songs. */
 
164
        if (queue.consume)
 
165
                DeleteOrder(pc, old_current);
 
166
}
 
167
 
 
168
void
 
169
playlist::PlayPrevious(PlayerControl &pc)
 
170
{
 
171
        if (!playing)
 
172
                return;
 
173
 
 
174
        assert(!queue.IsEmpty());
 
175
 
 
176
        int order;
 
177
        if (current > 0) {
 
178
                /* play the preceding song */
 
179
                order = current - 1;
 
180
        } else if (queue.repeat) {
 
181
                /* play the last song in "repeat" mode */
 
182
                order = queue.GetLength() - 1;
 
183
        } else {
 
184
                /* re-start playing the current song if it's
 
185
                   the first one */
 
186
                order = current;
 
187
        }
 
188
 
 
189
        PlayOrder(pc, order);
 
190
}
 
191
 
 
192
PlaylistResult
 
193
playlist::SeekSongPosition(PlayerControl &pc, unsigned song, float seek_time)
 
194
{
 
195
        if (!queue.IsValidPosition(song))
 
196
                return PlaylistResult::BAD_RANGE;
 
197
 
 
198
        const Song *queued_song = GetQueuedSong();
 
199
 
 
200
        unsigned i = queue.random
 
201
                ? queue.PositionToOrder(song)
 
202
                : song;
 
203
 
 
204
        pc.ClearError();
 
205
        stop_on_error = true;
 
206
        error_count = 0;
 
207
 
 
208
        if (!playing || (unsigned)current != i) {
 
209
                /* seeking is not within the current song - prepare
 
210
                   song change */
 
211
 
 
212
                playing = true;
 
213
                current = i;
 
214
 
 
215
                queued_song = nullptr;
 
216
        }
 
217
 
 
218
        Song *the_song = queue.GetOrder(i).DupDetached();
 
219
        if (!pc.Seek(the_song, seek_time)) {
 
220
                UpdateQueuedSong(pc, queued_song);
 
221
 
 
222
                return PlaylistResult::NOT_PLAYING;
 
223
        }
 
224
 
 
225
        queued = -1;
 
226
        UpdateQueuedSong(pc, nullptr);
 
227
 
 
228
        return PlaylistResult::SUCCESS;
 
229
}
 
230
 
 
231
PlaylistResult
 
232
playlist::SeekSongId(PlayerControl &pc, unsigned id, float seek_time)
 
233
{
 
234
        int song = queue.IdToPosition(id);
 
235
        if (song < 0)
 
236
                return PlaylistResult::NO_SUCH_SONG;
 
237
 
 
238
        return SeekSongPosition(pc, song, seek_time);
 
239
}
 
240
 
 
241
PlaylistResult
 
242
playlist::SeekCurrent(PlayerControl &pc, float seek_time, bool relative)
 
243
{
 
244
        if (!playing)
 
245
                return PlaylistResult::NOT_PLAYING;
 
246
 
 
247
        if (relative) {
 
248
                const auto status = pc.GetStatus();
 
249
 
 
250
                if (status.state != PlayerState::PLAY &&
 
251
                    status.state != PlayerState::PAUSE)
 
252
                        return PlaylistResult::NOT_PLAYING;
 
253
 
 
254
                seek_time += (int)status.elapsed_time;
 
255
        }
 
256
 
 
257
        if (seek_time < 0)
 
258
                seek_time = 0;
 
259
 
 
260
        return SeekSongPosition(pc, current, seek_time);
 
261
}