No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * rhythmbox
4 * Copyright (C) Alexandre Rosenfeld 2010 <alexandre.rosenfeld@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * The Rhythmbox authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Rhythmbox. This permission is above and beyond the permissions granted
14 * by the GPL license by which Rhythmbox is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 *
28 */
29
30 #include <sys/stat.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <math.h>
35
36 #include "rhythmdb.h"
37 #include "rb-shell.h"
38 #include "rb-shell-player.h"
39 #include "rb-daap-record.h"
40 #include "rb-playlist-manager.h"
41 #include "rb-play-queue-source.h"
42
43 #include <libdmapsharing/dmap.h>
44
45 #include "rb-dacp-player.h"
46
47 struct _RBDACPPlayerPrivate {
48 RBShell *shell;
49 RBShellPlayer *shell_player;
50 RBSource *play_queue;
51 };
52
53 static void rb_dacp_player_get_property (GObject *object, guint prop_id,
54 GValue *value, GParamSpec *pspec);
55 static void rb_dacp_player_set_property (GObject *object, guint prop_id,
56 const GValue *value, GParamSpec *pspec);
57
58 static void playing_song_changed (RBShellPlayer *shell_player, RhythmDBEntry *entry, RBDACPPlayer *player);
59 static void elapsed_changed (RBShellPlayer *shell_player, guint elapsed, RBDACPPlayer *player);
60
61 static DAAPRecord *rb_dacp_player_now_playing_record (DACPPlayer *player);
62 static const guchar *rb_dacp_player_now_playing_artwork (DACPPlayer *player, guint width, guint height);
63 static void rb_dacp_player_play_pause (DACPPlayer *player);
64 static void rb_dacp_player_pause (DACPPlayer *player);
65 static void rb_dacp_player_next_item (DACPPlayer *player);
66 static void rb_dacp_player_prev_item (DACPPlayer *player);
67
68 static void rb_dacp_player_cue_clear (DACPPlayer *player);
69 static void rb_dacp_player_cue_play (DACPPlayer *player, GList *records, guint index);
70
71 enum {
72 PROP_0,
73 PROP_PLAYING_TIME,
74 PROP_SHUFFLE_STATE,
75 PROP_REPEAT_STATE,
76 PROP_PLAY_STATE,
77 PROP_VOLUME
78 };
79
80 enum {
81 PLAYER_UPDATED,
82 LAST_SIGNAL
83 };
84
85 static guint signals[LAST_SIGNAL] = { 0 };
86
87 static void
88 rb_dacp_player_iface_init (gpointer iface, gpointer data)
89 {
90 DACPPlayerIface *dacp_player = iface;
91
92 g_assert (G_TYPE_FROM_INTERFACE (dacp_player) == DACP_TYPE_PLAYER);
93
94 dacp_player->now_playing_record = rb_dacp_player_now_playing_record;
95 dacp_player->now_playing_artwork = rb_dacp_player_now_playing_artwork;
96 dacp_player->play_pause = rb_dacp_player_play_pause;
97 dacp_player->pause = rb_dacp_player_pause;
98 dacp_player->next_item = rb_dacp_player_next_item;
99 dacp_player->prev_item = rb_dacp_player_prev_item;
100
101 dacp_player->cue_clear = rb_dacp_player_cue_clear;
102 dacp_player->cue_play = rb_dacp_player_cue_play;
103 }
104
105 G_DEFINE_DYNAMIC_TYPE_EXTENDED (RBDACPPlayer,
106 rb_dacp_player,
107 G_TYPE_OBJECT,
108 0,
109 G_IMPLEMENT_INTERFACE_DYNAMIC (DACP_TYPE_PLAYER,
110 rb_dacp_player_iface_init))
111
112 static void
113 rb_dacp_player_init (RBDACPPlayer *object)
114 {
115 object->priv = RB_DACP_PLAYER_GET_PRIVATE (object);
116 }
117
118 static void
119 rb_dacp_player_finalize (GObject *object)
120 {
121 RBDACPPlayer *player = RB_DACP_PLAYER (object);
122
123 g_signal_handlers_disconnect_by_func (player->priv->shell_player, playing_song_changed, player);
124
125 g_object_unref (player->priv->shell);
126 g_object_unref (player->priv->shell_player);
127
128 G_OBJECT_CLASS (rb_dacp_player_parent_class)->finalize (object);
129 }
130
131 static void
132 rb_dacp_player_class_init (RBDACPPlayerClass *klass)
133 {
134 GObjectClass* object_class = G_OBJECT_CLASS (klass);
135
136 g_type_class_add_private (klass, sizeof (RBDACPPlayerPrivate));
137
138 object_class->set_property = rb_dacp_player_set_property;
139 object_class->get_property = rb_dacp_player_get_property;
140 object_class->finalize = rb_dacp_player_finalize;
141
142 g_object_class_override_property (object_class, PROP_PLAYING_TIME, "playing-time");
143 g_object_class_override_property (object_class, PROP_SHUFFLE_STATE, "shuffle-state");
144 g_object_class_override_property (object_class, PROP_REPEAT_STATE, "repeat-state");
145 g_object_class_override_property (object_class, PROP_PLAY_STATE, "play-state");
146 g_object_class_override_property (object_class, PROP_VOLUME, "volume");
147
148 signals[PLAYER_UPDATED] =
149 g_signal_new ("player_updated",
150 G_OBJECT_CLASS_TYPE (object_class),
151 G_SIGNAL_RUN_LAST,
152 G_STRUCT_OFFSET (RBDACPPlayerClass, player_updated),
153 NULL, NULL,
154 g_cclosure_marshal_VOID__VOID,
155 G_TYPE_NONE, 0);
156
157 object_class->finalize = rb_dacp_player_finalize;
158 }
159
160 static void
161 rb_dacp_player_class_finalize (RBDACPPlayerClass *klass)
162 {
163 }
164
165 static void
166 rb_dacp_player_get_property (GObject *object,
167 guint prop_id,
168 GValue *value,
169 GParamSpec *pspec)
170 {
171 RBDACPPlayer *player = RB_DACP_PLAYER (object);
172
173 gboolean repeat;
174 gboolean shuffle;
175 guint playing_time;
176 gboolean playing;
177 gdouble volume;
178 RhythmDBEntry *entry;
179
180 switch (prop_id) {
181 case PROP_PLAYING_TIME:
182 rb_shell_player_get_playing_time (player->priv->shell_player, &playing_time, NULL);
183 g_value_set_ulong (value, playing_time * 1000);
184 break;
185 case PROP_SHUFFLE_STATE:
186 rb_shell_player_get_playback_state (player->priv->shell_player, &shuffle, &repeat);
187 g_value_set_boolean (value, shuffle);
188 break;
189 case PROP_REPEAT_STATE:
190 rb_shell_player_get_playback_state (player->priv->shell_player, &shuffle, &repeat);
191 g_value_set_enum (value, repeat ? DACP_REPEAT_ALL : DACP_REPEAT_NONE);
192 break;
193 case PROP_PLAY_STATE:
194 entry = rb_shell_player_get_playing_entry (player->priv->shell_player);
195 if (entry) {
196 g_object_get (player->priv->shell_player, "playing", &playing, NULL);
197 g_value_set_enum (value, playing ? DACP_PLAY_PLAYING : DACP_PLAY_PAUSED);
198 rhythmdb_entry_unref (entry);
199 } else {
200 g_value_set_enum (value, DACP_PLAY_STOPPED);
201 }
202 break;
203 case PROP_VOLUME:
204 rb_shell_player_get_volume (player->priv->shell_player, &volume, NULL);
205 g_value_set_ulong (value, (gulong) ceil (volume * 100.0));
206 break;
207 default:
208 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209 break;
210 }
211 }
212
213 static void
214 rb_dacp_player_set_property (GObject *object,
215 guint prop_id,
216 const GValue *value,
217 GParamSpec *pspec)
218 {
219 RBDACPPlayer *player = RB_DACP_PLAYER (object);
220
221 gboolean shuffle;
222 gboolean repeat;
223 gulong playing_time;
224 gdouble volume;
225
226 switch (prop_id) {
227 case PROP_PLAYING_TIME:
228 playing_time = g_value_get_ulong (value);
229 rb_shell_player_set_playing_time (player->priv->shell_player, (gulong) ceil (playing_time / 1000), NULL);
230 break;
231 case PROP_SHUFFLE_STATE:
232 rb_shell_player_get_playback_state (player->priv->shell_player, &shuffle, &repeat);
233 rb_shell_player_set_playback_state (player->priv->shell_player, g_value_get_boolean (value), repeat);
234 break;
235 case PROP_REPEAT_STATE:
236 rb_shell_player_get_playback_state (player->priv->shell_player, &shuffle, &repeat);
237 rb_shell_player_set_playback_state (player->priv->shell_player, shuffle, g_value_get_enum (value) != DACP_REPEAT_NONE);
238 break;
239 case PROP_VOLUME:
240 volume = ((double) g_value_get_ulong (value)) / 100.0;
241 rb_shell_player_set_volume (player->priv->shell_player, volume, NULL);
242 break;
243 default:
244 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
245 break;
246 }
247 }
248
249 static void
250 playing_song_changed (RBShellPlayer *shell_player,
251 RhythmDBEntry *entry,
252 RBDACPPlayer *player)
253 {
254 g_signal_emit (player, signals [PLAYER_UPDATED], 0);
255 }
256
257 static void
258 elapsed_changed (RBShellPlayer *shell_player,
259 guint elapsed,
260 RBDACPPlayer *player)
261 {
262 g_signal_emit (player, signals [PLAYER_UPDATED], 0);
263 }
264
265 RBDACPPlayer *
266 rb_dacp_player_new (RBShell *shell)
267 {
268 RBDACPPlayer *player;
269
270 player = RB_DACP_PLAYER (g_object_new (RB_TYPE_DACP_PLAYER, NULL));
271
272 player->priv->shell = g_object_ref (shell);
273 g_object_get (shell,
274 "shell-player", &player->priv->shell_player,
275 "queue-source", &player->priv->play_queue,
276 NULL);
277
278 g_signal_connect_object (player->priv->shell_player,
279 "playing-song-changed",
280 G_CALLBACK (playing_song_changed),
281 player,
282 0);
283 g_signal_connect_object (player->priv->shell_player,
284 "elapsed-changed",
285 G_CALLBACK (elapsed_changed),
286 player,
287 0);
288
289 return player;
290 }
291
292 static DAAPRecord *
293 rb_dacp_player_now_playing_record (DACPPlayer *player)
294 {
295 RhythmDBEntry *entry;
296 DAAPRecord *record;
297
298 entry = rb_shell_player_get_playing_entry (RB_DACP_PLAYER (player)->priv->shell_player);
299 if (entry == NULL) {
300 return NULL;
301 } else {
302 record = DAAP_RECORD (rb_daap_record_new (entry));
303 rhythmdb_entry_unref (entry);
304 return record;
305 }
306 }
307
308 static const guchar *
309 rb_dacp_player_now_playing_artwork (DACPPlayer *player, guint width, guint height)
310 {
311 return NULL;
312 }
313
314 static void
315 rb_dacp_player_play_pause (DACPPlayer *player)
316 {
317 rb_shell_player_playpause (RB_DACP_PLAYER (player)->priv->shell_player, FALSE, NULL);
318 }
319
320 static void
321 rb_dacp_player_pause (DACPPlayer *player)
322 {
323 rb_shell_player_pause (RB_DACP_PLAYER (player)->priv->shell_player, NULL);
324 }
325
326 static void
327 rb_dacp_player_next_item (DACPPlayer *player)
328 {
329 rb_shell_player_do_next (RB_DACP_PLAYER (player)->priv->shell_player, NULL);
330 }
331
332 static void
333 rb_dacp_player_prev_item (DACPPlayer *player)
334 {
335 rb_shell_player_do_previous (RB_DACP_PLAYER (player)->priv->shell_player, NULL);
336 }
337
338 static void
339 rb_dacp_player_cue_clear (DACPPlayer *player)
340 {
341 RBDACPPlayer *rbplayer;
342 rbplayer = RB_DACP_PLAYER (player);
343 rb_play_queue_source_clear_queue (RB_PLAY_QUEUE_SOURCE (rbplayer->priv->play_queue));
344 }
345
346 static void
347 rb_dacp_player_cue_play (DACPPlayer *player, GList *records, guint index)
348 {
349 GList *record;
350 gint current = 0;
351
352 for (record = records; record; record = record->next) {
353 gchar *location;
354 RBDACPPlayer *rbplayer;
355
356 g_object_get (record->data, "location", &location, NULL);
357 rbplayer = RB_DACP_PLAYER (player);
358 rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (rbplayer->priv->play_queue),
359 location,
360 -1);
361
362 if (current == index) {
363 RhythmDB *db;
364 RhythmDBEntry *entry;
365 RBPlayQueueSource *queue;
366 g_object_get (RB_DACP_PLAYER (player)->priv->shell,
367 "db", &db,
368 "queue-source", &queue,
369 NULL);
370 entry = rhythmdb_entry_lookup_by_location (db, location);
371 if (entry)
372 rb_shell_player_play_entry (RB_DACP_PLAYER (player)->priv->shell_player, entry, RB_SOURCE (queue));
373 g_object_unref (db);
374 g_object_unref (queue);
375 }
376
377 g_free (location);
378 current++;
379 }
380 }
381
382 void
383 _rb_dacp_player_register_type (GTypeModule *module)
384 {
385 rb_dacp_player_register_type (module);
386 }