Macro qtTrIdx() replaced by tr() and QT_TRANSLATE_NOOP()
[mafwsubrenderer] / mafw-gst-subtitles-renderer / libmafw-gst-renderer / mafw-gst-renderer-state-transitioning.c
1 /*
2  * This file is a part of MAFW
3  *
4  * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Visa Smolander <visa.smolander@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 #include <string.h>
26 #include "mafw-gst-renderer-state-transitioning.h"
27
28 #undef  G_LOG_DOMAIN
29 #define G_LOG_DOMAIN "mafw-gst-renderer-state-transitioning"
30
31 #define UPDATE_DELAY 10
32
33 /*----------------------------------------------------------------------------
34   Playback
35   ----------------------------------------------------------------------------*/
36
37 static void _do_play(MafwGstRendererState *self, GError **error);
38 static void _do_play_object(MafwGstRendererState *self, const gchar *object_id,
39                             GError **error);
40 static void _do_pause(MafwGstRendererState *self, GError **error);
41 static void _do_stop(MafwGstRendererState *self, GError **error);
42 static void _do_resume(MafwGstRendererState *self, GError **error);
43 static void _do_get_position(MafwGstRendererState *self, gint *seconds, 
44                              GError **error);
45
46 /*----------------------------------------------------------------------------
47   Playlist
48   ----------------------------------------------------------------------------*/
49
50 static void _do_next(MafwGstRendererState *self, GError **error);
51 static void _do_previous(MafwGstRendererState *self,GError **error);
52 static void _do_goto_index(MafwGstRendererState *self, guint index,
53                            GError **error);
54
55 /*----------------------------------------------------------------------------
56   Notification metatada
57   ----------------------------------------------------------------------------*/
58
59 static void _notify_metadata(MafwGstRendererState *self,
60                              const gchar *object_id,
61                              GHashTable *metadata,
62                              GError **error);
63
64 /*----------------------------------------------------------------------------
65   Notification worker
66   ----------------------------------------------------------------------------*/
67
68 static void _notify_play(MafwGstRendererState *self, GError **error);
69 static void _notify_pause(MafwGstRendererState *self,GError **error);
70
71 static void _notify_buffer_status(MafwGstRendererState *self,
72                                   gdouble percent,
73                                   GError **error);
74
75 /*----------------------------------------------------------------------------
76   Playlist editing signals
77   ----------------------------------------------------------------------------*/
78
79 static void _playlist_contents_changed(MafwGstRendererState *self,
80                                        gboolean clip_changed,
81                                        GError **error);
82
83 /*----------------------------------------------------------------------------
84   Property methods
85   ----------------------------------------------------------------------------*/
86
87 static GValue* _get_property_value(MafwGstRendererState *self,
88                                    const gchar *name);
89
90 /*----------------------------------------------------------------------------
91   GObject initialization
92   ----------------------------------------------------------------------------*/
93
94 G_DEFINE_TYPE(MafwGstRendererStateTransitioning,
95               mafw_gst_renderer_state_transitioning,
96               MAFW_TYPE_GST_RENDERER_STATE);
97
98 static void mafw_gst_renderer_state_transitioning_init(
99         MafwGstRendererStateTransitioning *self)
100 {
101 }
102
103 static void mafw_gst_renderer_state_transitioning_class_init(
104         MafwGstRendererStateTransitioningClass *klass)
105 {
106         MafwGstRendererStateClass *state_klass ;
107
108         state_klass = MAFW_GST_RENDERER_STATE_CLASS(klass);
109         g_return_if_fail(state_klass != NULL);
110
111         state_klass->name = g_strdup("Transitioning");
112
113         /* Playback */
114
115         state_klass->play         = _do_play;
116         state_klass->play_object  = _do_play_object;
117         state_klass->stop         = _do_stop;
118         state_klass->pause        = _do_pause;
119         state_klass->resume       = _do_resume;
120         state_klass->get_position = _do_get_position;
121
122         /* Playlist */
123
124         state_klass->next       = _do_next;
125         state_klass->previous   = _do_previous;
126         state_klass->goto_index = _do_goto_index;
127
128         /* Metadata */
129
130         state_klass->notify_metadata = _notify_metadata;
131
132         /* Notification worker */
133
134         state_klass->notify_play          = _notify_play;
135         state_klass->notify_pause         = _notify_pause;
136         state_klass->notify_buffer_status = _notify_buffer_status;
137
138         /* Playlist editing signals */
139
140         state_klass->playlist_contents_changed =
141                 _playlist_contents_changed;
142
143         /* Property methods */
144
145         state_klass->get_property_value = _get_property_value;
146 }
147
148 GObject *mafw_gst_renderer_state_transitioning_new(MafwGstRenderer *renderer)
149 {
150         MafwGstRendererState *state;
151
152         state = MAFW_GST_RENDERER_STATE(
153                 g_object_new(MAFW_TYPE_GST_RENDERER_STATE_TRANSITIONING, NULL));
154         state->renderer = renderer;
155
156         return G_OBJECT(state);
157 }
158
159 /*----------------------------------------------------------------------------
160   Playback
161   ----------------------------------------------------------------------------*/
162
163 static void _do_play(MafwGstRendererState *self, GError **error)
164 {
165         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
166         mafw_gst_renderer_state_do_play(self, error);
167 }
168
169 static void _do_play_object(MafwGstRendererState *self, const gchar *object_id,
170                             GError **error)
171 {
172         MafwGstRendererPlaybackMode cur_mode, prev_mode;
173
174         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
175
176         prev_mode = mafw_gst_renderer_get_playback_mode(self->renderer);
177         mafw_gst_renderer_state_do_play_object(self, object_id, error);
178         cur_mode = mafw_gst_renderer_get_playback_mode(self->renderer);
179
180         /* If this happens it means that we interrupted playlist playback
181          so let's resume it when play_object is finished */
182         if (cur_mode != prev_mode) {
183                 self->renderer->resume_playlist = TRUE;
184         }
185 }
186
187 static void _do_stop(MafwGstRendererState *self, GError **error)
188 {
189         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
190
191         /* Stop playback */
192         mafw_gst_renderer_state_do_stop(self, error);
193 }
194
195 static void _do_pause(MafwGstRendererState *self, GError **error)
196 {
197         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
198         g_debug("Got pause while transitioning");
199         self->renderer->worker->stay_paused = TRUE;
200 }
201
202 static void _do_resume(MafwGstRendererState *self, GError **error)
203 {
204         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
205         if (self->renderer->worker->stay_paused) {
206                 g_debug("Got resume while transitioning/paused");
207                 self->renderer->worker->stay_paused = FALSE;
208         } else {
209                 g_set_error(error, MAFW_RENDERER_ERROR,
210                             MAFW_RENDERER_ERROR_CANNOT_PLAY,
211                             "cannot resume in transitioning state without "
212                             "having paused before");
213         }
214 }
215
216 static void _do_get_position(MafwGstRendererState *self, gint *seconds, 
217                              GError **error)
218 {
219         *seconds = 0;
220 }
221
222 /*----------------------------------------------------------------------------
223   Playlist
224   ----------------------------------------------------------------------------*/
225
226 static void _do_next(MafwGstRendererState *self, GError **error)
227 {
228         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
229         mafw_gst_renderer_state_do_next(self, error);
230 }
231
232 static void _do_previous(MafwGstRendererState *self, GError **error)
233 {
234         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
235         mafw_gst_renderer_state_do_prev(self, error);
236 }
237
238 static void _do_goto_index(MafwGstRendererState *self, guint index,
239                            GError **error)
240 {
241         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
242         mafw_gst_renderer_state_do_goto_index(self, index, error);
243 }
244
245 /*----------------------------------------------------------------------------
246   Notification metatada
247   ----------------------------------------------------------------------------*/
248
249 static void _notify_metadata(MafwGstRendererState *self,
250                              const gchar *object_id,
251                              GHashTable *metadata,
252                              GError **error)
253 {
254         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
255
256         MafwGstRenderer *renderer;
257         GValue *mval;
258         gpointer value;
259         gint nuris, i;
260         gchar **uris;
261         gchar *uri;
262
263         g_debug("running _notify_metadata...");
264
265         renderer = MAFW_GST_RENDERER_STATE(self)->renderer;
266
267         /* If we have received metadata for the item that we are playing
268            then play it */
269         if (object_id && renderer->media->object_id &&
270             !strcmp(object_id, renderer->media->object_id)) {
271                 /* Check how many uris provide the object_id */
272                 value = g_hash_table_lookup(metadata, MAFW_METADATA_KEY_URI);
273                 nuris = mafw_metadata_nvalues(value);
274                 if (nuris == 1) {
275                         mval = mafw_metadata_first(metadata,
276                                                    MAFW_METADATA_KEY_URI);
277                         g_assert(mval);
278                         g_free(renderer->media->uri);
279                         renderer->media->uri =
280                                 g_strdup(g_value_get_string(mval));
281                         uri = renderer->media->uri;
282                 } else if (nuris > 1) {
283                         uris = g_new0(gchar *, nuris + 1);
284                         for (i = 0; i < nuris; i++) {
285                                 mval = g_value_array_get_nth(value, i);
286                                 uris[i] = (gchar *) g_value_get_string(mval);
287                         }
288
289                         /* Try the first URI, if that fails to play back another
290                          * one will be selected until we get a successful one or
291                          * all failed. On success, the selected URI will be
292                          * emitted as metadata */
293                         g_free(renderer->media->uri);
294                         renderer->media->uri = g_strdup(uris[0]);
295                 } else {
296                         g_assert_not_reached();
297                 }
298
299                 /* Set seekability property; currently, if several uris are
300                  * provided it uses the value of the first uri. If later another
301                  * uri is actually played, then this value should be changed. */
302                 mval = mafw_metadata_first(metadata,
303                                            MAFW_METADATA_KEY_IS_SEEKABLE);
304                 if (mval != NULL) {
305                         renderer->media->seekability =
306                                 g_value_get_boolean(mval) ?
307                                 SEEKABILITY_SEEKABLE : SEEKABILITY_NO_SEEKABLE;
308                         g_debug("_notify_metadata: source seekability %d",
309                                 renderer->media->seekability);
310                 } else {
311                         renderer->media->seekability = SEEKABILITY_UNKNOWN;
312                         g_debug("_notify_metadata: source seekability unknown");
313                 }
314
315                 /* Check for source duration to keep it updated if needed */
316                 mval = mafw_metadata_first(metadata,
317                                            MAFW_METADATA_KEY_DURATION);
318
319                 if (mval != NULL) {
320                         renderer->media->duration = g_value_get_int(mval);
321                         g_debug("_notify_metadata: source duration %d",
322                                 renderer->media->duration);
323                 } else {
324                         renderer->media->duration = -1;
325                         g_debug("_notify_metadata: source duration unknown");
326                 }
327
328                 /* Play the available uri(s) */
329                 if (nuris == 1) {
330                         mafw_gst_renderer_worker_play(renderer->worker, uri, NULL);
331                 } else {
332                         mafw_gst_renderer_worker_play_alternatives(
333                                 renderer->worker, uris);
334                         g_free(uris);
335                 }
336         }
337 }
338
339 /*----------------------------------------------------------------------------
340   Notification worker
341   ----------------------------------------------------------------------------*/
342
343 static void _notify_play(MafwGstRendererState *self, GError **error)
344 {
345         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
346
347         MafwGstRenderer *renderer = MAFW_GST_RENDERER_STATE(self)->renderer;
348
349         if (renderer->media->object_id)
350         {
351                 renderer->update_playcount_id = g_timeout_add_seconds(
352                         UPDATE_DELAY,
353                         mafw_gst_renderer_update_stats,
354                         renderer);
355         }
356
357         mafw_gst_renderer_set_state(renderer, Playing);
358 }
359
360 static void _notify_pause(MafwGstRendererState *self, GError **error)
361 {
362         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
363
364         MafwGstRenderer *renderer = MAFW_GST_RENDERER_STATE(self)->renderer;
365         self->renderer->worker->stay_paused = FALSE;
366         mafw_gst_renderer_set_state(renderer, Paused);
367 }
368
369 static void _notify_buffer_status(MafwGstRendererState *self, gdouble percent,
370                                   GError **error)
371 {
372         mafw_gst_renderer_state_do_notify_buffer_status (self, percent, error);
373 }
374
375 /*----------------------------------------------------------------------------
376   Playlist editing signals
377   ----------------------------------------------------------------------------*/
378
379 static void _playlist_contents_changed(MafwGstRendererState *self,
380                                        gboolean clip_changed,
381                                        GError **error)
382 {
383         MafwGstRendererPlaybackMode mode;
384
385         g_return_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self));
386
387         /* Play the new index only if we are not in standalone mode.
388            Otherwise, when play_object finishes the new item will be
389            played if that's been suggested with renderer->resume_playlist */
390         mode = mafw_gst_renderer_get_playback_mode(self->renderer);
391         if (clip_changed && mode == MAFW_GST_RENDERER_MODE_PLAYLIST) {
392                 mafw_gst_renderer_state_do_play(self, error);
393         }
394 }
395
396 /*----------------------------------------------------------------------------
397   Property methods
398   ----------------------------------------------------------------------------*/
399
400 GValue* _get_property_value(MafwGstRendererState *self, const gchar *name)
401 {
402         GValue *value = NULL;
403
404         g_return_val_if_fail(MAFW_IS_GST_RENDERER_STATE_TRANSITIONING(self),
405                 value);
406
407         if (!g_strcmp0(name, MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS)) {
408                 value = g_new0(GValue, 1);
409                 g_value_init(value, G_TYPE_STRING);
410                 g_value_set_string(value, "");
411         }
412
413         return value;
414 }