2 * Dictix / DixPlayer - dix-player.c
4 * Copyright (C) Martin Blanchard 2011 <tinram@gmx.fr>
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.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
30 #include <glib/gi18n.h>
34 #include "dix-player.h"
43 static guint signals
[LAST_SIGNAL
] = { 0 };
45 struct _DixPlayerPrivate
54 GstElement
*converter
;
55 GstElement
*resampler
;
59 #define DIX_PLAYER_GET_PRIVATE(obj) \
60 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), DIX_TYPE_PLAYER, DixPlayerPrivate))
62 G_DEFINE_TYPE (DixPlayer
, dix_player
, GST_TYPE_PIPELINE
)
64 static void dix_player_error_cb (GstBus
*bus
, GstMessage
*message
, gpointer data
);
65 static void dix_player_state_changed_cb (GstBus
*bus
, GstMessage
*message
, gpointer data
);
66 static void dix_player_eos_cb (GstBus
*bus
, GstMessage
*message
, gpointer data
);
69 dix_player_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
71 DixPlayer
*player
= (DixPlayer
*) object
;
72 DixPlayerPrivate
*priv
= player
->priv
;
76 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
82 dix_player_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
84 DixPlayer
*player
= (DixPlayer
*) object
;
85 DixPlayerPrivate
*priv
= player
->priv
;
89 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
95 dix_player_dispose (GObject
*object
)
97 DixPlayer
*player
= (DixPlayer
*) object
;
98 DixPlayerPrivate
*priv
= player
->priv
;
100 if (priv
->bus
!= NULL
) {
101 gst_object_unref (GST_OBJECT (priv
->bus
));
105 G_OBJECT_CLASS (dix_player_parent_class
)->dispose (object
);
109 dix_player_class_init (DixPlayerClass
* klass
)
111 GObjectClass
*gobject_class
= (GObjectClass
*) klass
;
113 gobject_class
->set_property
= dix_player_set_property
;
114 gobject_class
->get_property
= dix_player_get_property
;
115 gobject_class
->dispose
= dix_player_dispose
;
117 signals
[PLAYBACK_STARTED
] = g_signal_new ("playback-started",
118 G_TYPE_FROM_CLASS (gobject_class
),
120 G_STRUCT_OFFSET (DixPlayerClass
, playback_started
),
122 g_cclosure_marshal_VOID__VOID
,
125 signals
[PLAYBACK_STOPPED
] = g_signal_new ("playback-stopped",
126 G_TYPE_FROM_CLASS (gobject_class
),
128 G_STRUCT_OFFSET (DixPlayerClass
, playback_stopped
),
130 g_cclosure_marshal_VOID__BOOLEAN
,
131 G_TYPE_NONE
, 1, G_TYPE_BOOLEAN
);
133 /*signals[PIPELINE_ERROR] = g_signal_new ("pipeline-error",
134 G_TYPE_FROM_CLASS (gobject_class),
136 G_STRUCT_OFFSET (DixPlayerClass, record_stopped),
138 g_cclosure_marshal_VOID__POINTER,
139 1, DIX_ERROR, G_TYPE_NONE, 0);*/
141 g_type_class_add_private (gobject_class
, sizeof (DixPlayerPrivate
));
145 dix_player_init (DixPlayer
* player
)
147 DixPlayerPrivate
*priv
= DIX_PLAYER_GET_PRIVATE (player
);
150 gst_object_set_name (GST_OBJECT(player
), "DictixPlayer");
152 priv
->now_playing
= FALSE
;
153 priv
->stopping
= FALSE
;
158 priv
->decoder
= NULL
;
159 priv
->converter
= NULL
;
160 priv
->resampler
= NULL
;
167 return g_object_new (DIX_TYPE_PLAYER
, NULL
);
171 dix_player_start_playing (DixPlayer
*player
, gchar
* uri
, GError
**error
) /* GError ! */
173 g_return_if_fail (DIX_IS_PLAYER (player
));
174 DixPlayerPrivate
*priv
= player
->priv
;
177 if (g_str_has_suffix (uri
, ".flac") == FALSE
) {
178 g_warning ("Player only handles FLAC audio files.");
184 if (G_UNLIKELY (priv
->bus
== NULL
)) {
185 priv
->source
= gst_element_factory_make ("giosrc", "DictixPlayerSource");
186 priv
->decoder
= gst_element_factory_make ("flacdec", "DictixPlayerDecoder");
187 priv
->converter
= gst_element_factory_make ("audioconvert", "DictixPlayerConverter");
188 priv
->resampler
= gst_element_factory_make ("audioresample", "DictixPlayerResampler");
189 priv
->sink
= gst_element_factory_make ("pulsesink", "DictixPlayerSink");
191 if (priv
->source
== NULL
|| priv
->decoder
== NULL
192 || priv
->converter
== NULL
|| priv
->resampler
== NULL
193 || priv
->sink
== NULL
) {
197 gst_bin_add_many (GST_BIN (player
),
205 gst_element_link_many (priv
->source
,
213 priv
->bus
= gst_pipeline_get_bus (GST_PIPELINE (player
));
214 gst_bus_add_signal_watch (priv
->bus
);
215 g_signal_connect (priv
->bus
, "message::error",
216 G_CALLBACK (dix_player_error_cb
), player
);
217 g_signal_connect (priv
->bus
, "message::state-changed",
218 G_CALLBACK (dix_player_state_changed_cb
), player
);
219 g_signal_connect (priv
->bus
, "message::eos",
220 G_CALLBACK (dix_player_eos_cb
), player
);
224 if (priv
->now_playing
== TRUE
) {
225 gst_element_set_state (GST_ELEMENT (player
), GST_STATE_NULL
);
226 gst_element_get_state (GST_ELEMENT (player
), NULL
, NULL
, -1); /*FIXME: Move it async !*/
229 g_object_set (G_OBJECT (priv
->source
), "location", uri
, NULL
);
232 gst_element_set_state (GST_ELEMENT (player
), GST_STATE_PLAYING
);
236 dix_player_query_duration (DixPlayer
*player
)
238 g_return_val_if_fail (DIX_IS_PLAYER (player
), -1);
239 DixPlayerPrivate
*priv
= player
->priv
;
240 GstFormat format
= GST_FORMAT_TIME
;
243 if (G_UNLIKELY (priv
->now_playing
== FALSE
)) {
247 if (gst_element_query_duration (GST_ELEMENT (player
), &format
, &duration
)) {
248 if (format
!= GST_FORMAT_TIME
) {
252 return duration
/ GST_SECOND
;
259 dix_player_query_position (DixPlayer
*player
)
261 g_return_val_if_fail (DIX_IS_PLAYER (player
), -1);
262 DixPlayerPrivate
*priv
= player
->priv
;
263 GstFormat format
= GST_FORMAT_TIME
;
266 if (G_UNLIKELY (priv
->now_playing
== FALSE
)) {
270 if (gst_element_query_position (GST_ELEMENT (player
), &format
, &position
)) {
271 if (format
!= GST_FORMAT_TIME
) {
275 return position
/ GST_SECOND
;
282 dix_player_query_progress (DixPlayer
*player
, gint64
*position
)
284 g_return_val_if_fail (DIX_IS_PLAYER (player
), -1.0);
285 DixPlayerPrivate
*priv
= player
->priv
;
286 GstFormat format
= GST_FORMAT_TIME
;
290 if (G_UNLIKELY (priv
->now_playing
== FALSE
)) {
294 gst_element_query_position (GST_ELEMENT (player
), &format
, ¤t
);
295 gst_element_query_duration (GST_ELEMENT (player
), &format
, &duration
);
297 if (position
!= NULL
) {
298 *position
= current
/ GST_SECOND
;
301 return (gdouble
) current
/ (gdouble
) duration
;
305 dix_player_move (DixPlayer
*player
, gdouble location
)
307 g_return_if_fail (DIX_IS_PLAYER (player
));
308 DixPlayerPrivate
*priv
= player
->priv
;
309 GstFormat format
= GST_FORMAT_TIME
;
312 if (G_UNLIKELY (priv
->now_playing
== FALSE
)) {
316 gst_element_query_duration (GST_ELEMENT (player
), &format
, &duration
);
318 gst_element_seek (GST_ELEMENT (player
),
323 (gint64
) ((gdouble
) duration
* location
),
329 dix_player_pause (DixPlayer
*player
)
331 g_return_if_fail (DIX_IS_PLAYER (player
));
332 DixPlayerPrivate
*priv
= player
->priv
;
334 if (G_UNLIKELY (priv
->now_playing
== FALSE
)) {
338 gst_element_set_state (GST_ELEMENT (player
), GST_STATE_PAUSED
);
342 dix_player_stop (DixPlayer
*player
)
344 g_return_if_fail (DIX_IS_PLAYER (player
));
345 DixPlayerPrivate
*priv
= player
->priv
;
346 GstMessage
*message
= NULL
, *fake
;
348 if (G_UNLIKELY (priv
->now_playing
== FALSE
)) {
352 priv
->stopping
= TRUE
;
354 gst_element_set_state (priv
->source
, GST_STATE_NULL
);
355 gst_element_get_state (priv
->source
, NULL
, NULL
, GST_CLOCK_TIME_NONE
);
356 gst_element_set_locked_state (priv
->source
, TRUE
);
358 /* We have to simulate eos now that source isn't streaming anymore: */
359 fake
= gst_message_new_eos (GST_OBJECT (priv
->source
));
360 gst_bus_post (priv
->bus
, fake
);
363 message
= gst_bus_pop (priv
->bus
);
365 if (message
!= NULL
) {
366 gst_bus_async_signal_func (priv
->bus
, message
, player
);
368 } while (message
!= NULL
);
370 priv
->stopping
= FALSE
;
374 dix_player_set_volume (DixPlayer
*player
, gdouble volume
)
376 g_return_if_fail (DIX_IS_PLAYER (player
));
377 g_return_if_fail (volume
>= 0.0);
378 DixPlayerPrivate
*priv
= player
->priv
;
380 if (priv
->bus
!= NULL
) {
381 g_object_set (G_OBJECT (priv
->sink
), "volume", volume
, NULL
);
386 dix_player_error_cb (GstBus
*bus
, GstMessage
*message
, gpointer data
)
388 DixPlayer
*player
= (DixPlayer
*) data
;
389 DixPlayerPrivate
*priv
= player
->priv
;
392 /* error = g_error_new (DIX_ERROR, DIX_ERROR_GST_INTERNAL,*/
393 /* _("Audio engine internal error"));*/
397 dix_player_state_changed_cb (GstBus
*bus
, GstMessage
*message
, gpointer data
)
399 DixPlayer
*player
= (DixPlayer
*) data
;
400 DixPlayerPrivate
*priv
= player
->priv
;
403 gst_message_parse_state_changed (message
, NULL
, &state
, NULL
);
405 if (message
->src
!= GST_OBJECT (player
)) {
410 case GST_STATE_NULL
: {
412 } case GST_STATE_READY
: {
414 } case GST_STATE_PLAYING
: {
415 priv
->now_playing
= TRUE
;
416 g_signal_emit (player
, signals
[PLAYBACK_STARTED
], 0);
418 } case GST_STATE_PAUSED
: {
419 if (priv
->stopping
== FALSE
) {
420 g_signal_emit (player
, signals
[PLAYBACK_STOPPED
], 0, FALSE
);
430 dix_player_eos_cb (GstBus
*bus
, GstMessage
*message
, gpointer data
)
432 DixPlayer
*player
= (DixPlayer
*) data
;
433 DixPlayerPrivate
*priv
= player
->priv
;
435 gst_element_set_state (GST_ELEMENT (player
), GST_STATE_NULL
);
436 gst_element_get_state (GST_ELEMENT (player
), NULL
, NULL
, GST_CLOCK_TIME_NONE
);
438 priv
->now_playing
= FALSE
;
439 g_signal_emit (player
, signals
[PLAYBACK_STOPPED
], 0, TRUE
);
441 gst_element_set_locked_state (priv
->source
, FALSE
);