2 * Copyright (C) 2006-2008 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
25 #include "swfdec_loader_internal.h"
26 #include "swfdec_buffer.h"
27 #include "swfdec_debug.h"
28 #include "swfdec_stream_target.h"
29 #include "swfdec_player_internal.h"
34 * SECTION:SwfdecStream
35 * @title: SwfdecStream
36 * @short_description: object used for input
38 * SwfdecStream is the base class used for communication inside Swfdec. If you
39 * are a UNIX developer, think of this class as the equivalent to a file
40 * descriptor. #SwfdecLoader and #SwfdecSocket are the subclasses supposed to
41 * be used for files or network sockets, respectively.
43 * This class provides the functions necessary to implement subclasses of
44 * streams. None of the functions described in this section should be used by
45 * anything but subclass implementations. Consider them "protected".
51 * This is the base object used for providing input. It is abstract, use a
52 * subclass to provide your input. All members are considered private.
57 * @describe: Provide a string describing your string. Default implementations
58 * of this function exist for both the #SwfdecLoader and
59 * #SwfdecStream subclasses. They return the URL for the stream.
60 * @close: Called when Swfdec requests that the stream be closed. After this
61 * function was called, Swfdec will consider the stream finished and
62 * will not ever read data from it again.
64 * This is the base class used for providing input. You are supposed to create
65 * a subclass that fills in the function pointers mentioned above.
68 /*** SwfdecStream ***/
71 SWFDEC_STREAM_STATE_CONNECTING
= 0, /* stream is still in the process of establishing a connection */
72 SWFDEC_STREAM_STATE_OPEN
, /* stream is open and data flow is happening */
73 SWFDEC_STREAM_STATE_CLOSED
, /* loader has been closed */
74 SWFDEC_STREAM_STATE_ERROR
/* loader is in error state */
77 struct _SwfdecStreamPrivate
79 SwfdecPlayer
* player
; /* player to queue target notificaions in */
80 SwfdecStreamTarget
* target
; /* SwfdecStreamTarget that gets notified about loading progress */
81 SwfdecStreamState state
; /* SwfdecStreamState the stream is currently in */
82 SwfdecStreamState processed_state
;/* SwfdecStreamState the target knows about */
83 gboolean queued
; /* TRUE if we have queued an action already */
84 char * error
; /* error message if in error state or NULL */
85 SwfdecBufferQueue
* queue
; /* SwfdecBufferQueue managing the input buffers */
95 G_DEFINE_ABSTRACT_TYPE (SwfdecStream
, swfdec_stream
, G_TYPE_OBJECT
)
98 swfdec_stream_get_property (GObject
*object
, guint param_id
, GValue
*value
,
101 SwfdecStreamPrivate
*stream
= SWFDEC_STREAM (object
)->priv
;
105 g_value_set_string (value
, stream
->error
);
108 g_value_set_boolean (value
, stream
->state
== SWFDEC_STREAM_STATE_OPEN
);
111 g_value_set_boolean (value
, stream
->state
== SWFDEC_STREAM_STATE_CLOSED
);
114 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
120 swfdec_stream_set_property (GObject
*object
, guint param_id
, const GValue
*value
,
123 //SwfdecStream *stream = SWFDEC_STREAM (object);
127 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
133 swfdec_stream_dispose (GObject
*object
)
135 SwfdecStreamPrivate
*stream
= SWFDEC_STREAM (object
)->priv
;
137 /* targets are supposed to keep a reference around */
138 g_assert (stream
->target
== NULL
);
140 swfdec_buffer_queue_unref (stream
->queue
);
141 stream
->queue
= NULL
;
143 g_free (stream
->error
);
144 stream
->error
= NULL
;
146 G_OBJECT_CLASS (swfdec_stream_parent_class
)->dispose (object
);
150 swfdec_stream_class_init (SwfdecStreamClass
*klass
)
152 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
154 g_type_class_add_private (klass
, sizeof (SwfdecStreamPrivate
));
156 object_class
->dispose
= swfdec_stream_dispose
;
157 object_class
->get_property
= swfdec_stream_get_property
;
158 object_class
->set_property
= swfdec_stream_set_property
;
160 g_object_class_install_property (object_class
, PROP_ERROR
,
161 g_param_spec_string ("error", "error", "NULL when no error or string describing error",
162 NULL
, G_PARAM_READABLE
));
163 g_object_class_install_property (object_class
, PROP_OPEN
,
164 g_param_spec_boolean ("open", "open", "TRUE while data is flowing",
165 FALSE
, G_PARAM_READABLE
));
166 g_object_class_install_property (object_class
, PROP_COMPLETE
,
167 g_param_spec_boolean ("complete", "complete", "TRUE when all data has been transmitted",
168 FALSE
, G_PARAM_READABLE
));
172 swfdec_stream_init (SwfdecStream
*stream
)
174 SwfdecStreamPrivate
*priv
;
176 stream
->priv
= priv
= G_TYPE_INSTANCE_GET_PRIVATE (stream
, SWFDEC_TYPE_STREAM
, SwfdecStreamPrivate
);
178 priv
->queue
= swfdec_buffer_queue_new ();
181 /*** INTERNAL API ***/
184 swfdec_stream_get_queue (SwfdecStream
*stream
)
186 g_return_val_if_fail (SWFDEC_IS_STREAM (stream
), NULL
);
188 return stream
->priv
->queue
;
191 static void swfdec_stream_queue_processing (SwfdecStream
*stream
);
194 swfdec_stream_process (gpointer streamp
, gpointer unused
)
196 SwfdecStream
*stream
= streamp
;
197 SwfdecStreamPrivate
*priv
= stream
->priv
;
199 g_assert (priv
->target
!= NULL
);
201 priv
->queued
= FALSE
;
202 if (priv
->state
== priv
->processed_state
&&
203 priv
->state
!= SWFDEC_STREAM_STATE_OPEN
)
205 g_assert (priv
->processed_state
!= SWFDEC_STREAM_STATE_CLOSED
);
206 g_object_ref (stream
);
207 if (priv
->state
== SWFDEC_STREAM_STATE_ERROR
) {
208 swfdec_stream_target_error (priv
->target
, stream
);
210 while (priv
->state
!= priv
->processed_state
) {
211 if (priv
->processed_state
== SWFDEC_STREAM_STATE_CONNECTING
) {
212 priv
->processed_state
= SWFDEC_STREAM_STATE_OPEN
;
213 swfdec_stream_target_open (priv
->target
, stream
);
214 } else if (priv
->processed_state
== SWFDEC_STREAM_STATE_OPEN
) {
215 if (swfdec_stream_target_parse (priv
->target
, stream
)) {
216 swfdec_stream_queue_processing (stream
);
218 } else if (priv
->target
) {
219 priv
->processed_state
= SWFDEC_STREAM_STATE_CLOSED
;
220 swfdec_stream_target_close (priv
->target
, stream
);
226 if (priv
->processed_state
== SWFDEC_STREAM_STATE_OPEN
) {
227 if (swfdec_stream_target_parse (priv
->target
, stream
)) {
228 swfdec_stream_queue_processing (stream
);
233 g_object_unref (stream
);
237 swfdec_stream_queue_processing (SwfdecStream
*stream
)
239 SwfdecStreamPrivate
*priv
= stream
->priv
;
245 g_assert (priv
->player
);
246 swfdec_player_add_external_action (priv
->player
, stream
,
247 swfdec_stream_process
, NULL
);
252 swfdec_stream_ensure_closed (SwfdecStream
*stream
)
254 SwfdecStreamPrivate
*priv
;
255 SwfdecStreamClass
*klass
;
257 g_return_if_fail (SWFDEC_IS_STREAM (stream
));
260 if (priv
->state
== SWFDEC_STREAM_STATE_ERROR
||
261 priv
->state
== SWFDEC_STREAM_STATE_CLOSED
)
264 klass
= SWFDEC_STREAM_GET_CLASS (stream
);
267 klass
->close (stream
);
268 priv
->state
= SWFDEC_STREAM_STATE_CLOSED
;
269 priv
->processed_state
= SWFDEC_STREAM_STATE_CLOSED
;
273 swfdec_stream_set_target (SwfdecStream
*stream
, SwfdecStreamTarget
*target
)
275 SwfdecStreamPrivate
*priv
;
277 g_return_if_fail (SWFDEC_IS_STREAM (stream
));
278 if (target
!= NULL
) {
279 g_return_if_fail (stream
->priv
->processed_state
== SWFDEC_STREAM_STATE_CONNECTING
);
280 g_return_if_fail (SWFDEC_IS_STREAM_TARGET (target
));
285 swfdec_player_remove_all_external_actions (priv
->player
, stream
);
287 priv
->queued
= FALSE
;
288 priv
->target
= target
;
290 priv
->player
= swfdec_stream_target_get_player (target
);
291 if (priv
->state
!= SWFDEC_STREAM_STATE_CONNECTING
)
292 swfdec_stream_queue_processing (stream
);
301 * swfdec_stream_describe:
302 * @stream: a #SwfdecStream
304 * Describes the stream in a simple string. This is mostly useful for debugging
307 * Returns: a constant string describing the stream
310 swfdec_stream_describe (SwfdecStream
*stream
)
312 SwfdecStreamClass
*klass
;
314 g_return_val_if_fail (SWFDEC_IS_STREAM (stream
), NULL
);
316 klass
= SWFDEC_STREAM_GET_CLASS (stream
);
317 g_return_val_if_fail (klass
->describe
, NULL
);
319 return klass
->describe (stream
);
323 * swfdec_stream_error:
324 * @stream: a #SwfdecStream
325 * @error: a printf-style string describing the error
326 * @...: arguments for the @error string
328 * Moves the stream in the error state if it wasn't before. A stream that is in
329 * the error state will not process any more data. Also, internal error
330 * handling scripts may be executed.
333 swfdec_stream_error (SwfdecStream
*stream
, const char *error
, ...)
337 g_return_if_fail (SWFDEC_IS_STREAM (stream
));
338 g_return_if_fail (error
!= NULL
);
340 va_start (args
, error
);
341 swfdec_stream_errorv (stream
, error
, args
);
346 * swfdec_stream_errorv:
347 * @stream: a #SwfdecStream
348 * @error: a printf-style error string
349 * @args: arguments for @error
351 * This function is the va_list alternative to swfdec_stream_error(). See that
352 * function for details.
355 swfdec_stream_errorv (SwfdecStream
*stream
, const char *error
, va_list args
)
357 SwfdecStreamPrivate
*priv
;
360 g_return_if_fail (SWFDEC_IS_STREAM (stream
));
361 g_return_if_fail (error
!= NULL
);
363 real_error
= g_strdup_vprintf (error
, args
);
366 SWFDEC_ERROR ("another error in stream for %s: %s",
367 swfdec_stream_describe (stream
), real_error
);
372 SWFDEC_ERROR ("error in stream for %s: %s",
373 swfdec_stream_describe (stream
), real_error
);
374 priv
->state
= SWFDEC_STREAM_STATE_ERROR
;
375 priv
->error
= real_error
;
376 swfdec_stream_queue_processing (stream
);
380 * swfdec_stream_open:
381 * @stream: a #SwfdecStream
383 * Call this function when your stream opened the resulting file. For HTTP this
384 * is when having received the headers. You must call this function before
385 * swfdec_stream_push() can be called.
388 swfdec_stream_open (SwfdecStream
*stream
)
390 g_return_if_fail (SWFDEC_IS_STREAM (stream
));
391 g_return_if_fail (stream
->priv
->state
== SWFDEC_STREAM_STATE_CONNECTING
);
393 stream
->priv
->state
= SWFDEC_STREAM_STATE_OPEN
;
394 g_object_notify (G_OBJECT (stream
), "open");
395 swfdec_stream_queue_processing (stream
);
399 * swfdec_stream_is_open:
400 * @stream: a #SwfdecStream
402 * Checks if the given @stream is currrently open. Some functions, for example
403 * swfdec_socket_send(), require an open stream.
405 * Returns: %TRUE if the stream is open, %FALSE otherwise.
408 swfdec_stream_is_open (SwfdecStream
*stream
)
410 g_return_val_if_fail (SWFDEC_IS_STREAM (stream
), FALSE
);
412 return stream
->priv
->state
== SWFDEC_STREAM_STATE_OPEN
;
416 * swfdec_stream_is_complete:
417 * @stream: a #SwfdecStream
419 * Checks if all data has successfully been transmitted through the @stream
420 * and it has been closed.
422 * Returns: %TRUE if the stream is completed, %FALSE otherwise.
425 swfdec_stream_is_complete (SwfdecStream
*stream
)
427 g_return_val_if_fail (SWFDEC_IS_STREAM (stream
), FALSE
);
429 return stream
->priv
->state
== SWFDEC_STREAM_STATE_CLOSED
;
433 * swfdec_stream_push:
434 * @stream: a #SwfdecStream
435 * @buffer: new data to make available. The stream takes the reference
438 * Makes the data in @buffer available to @stream and processes it. The @stream
442 swfdec_stream_push (SwfdecStream
*stream
, SwfdecBuffer
*buffer
)
444 g_return_if_fail (SWFDEC_IS_STREAM (stream
));
445 g_return_if_fail (stream
->priv
->state
== SWFDEC_STREAM_STATE_OPEN
);
446 g_return_if_fail (buffer
!= NULL
);
448 swfdec_buffer_queue_push (stream
->priv
->queue
, buffer
);
450 if (SWFDEC_IS_LOADER (stream
))
451 g_object_notify (G_OBJECT (stream
), "loaded");
452 swfdec_stream_queue_processing (stream
);
456 * swfdec_stream_close:
457 * @stream: a #SwfdecStream
459 * Indicates to @stream that no more data will follow. The stream must be open.
462 swfdec_stream_close (SwfdecStream
*stream
)
464 g_return_if_fail (SWFDEC_IS_STREAM (stream
));
465 g_return_if_fail (stream
->priv
->state
== SWFDEC_STREAM_STATE_OPEN
);
467 stream
->priv
->state
= SWFDEC_STREAM_STATE_CLOSED
;
468 g_object_notify (G_OBJECT (stream
), "open");
469 g_object_notify (G_OBJECT (stream
), "complete");
470 swfdec_stream_queue_processing (stream
);