hythmbox-2.98/plugins/daap/rb-dacp-player.c

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 }