[Swfdec-commits] Branch 'rtmp' - 135 commits - configure.ac swfdec-gtk/swfdec_gtk_socket.c swfdec/Makefile.am swfdec/swfdec_amf.c swfdec/swfdec_amf.h swfdec/swfdec_as_array.c swfdec/swfdec_as_internal.h swfdec/swfdec_as_interpret.c swfdec/swfdec_as_object.c swfdec/swfdec_as_strings.c swfdec/swfdec_as_super.c swfdec/swfdec_as_types.h swfdec/swfdec_audio.c swfdec/swfdec_audio_decoder_adpcm.c swfdec/swfdec_audio_decoder.c swfdec/swfdec_audio_decoder_gst.c swfdec/swfdec_audio_decoder.h swfdec/swfdec_audio_decoder_uncompressed.c swfdec/swfdec_audio_flv.c swfdec/swfdec_audio_flv.h swfdec/swfdec_audio_internal.h swfdec/swfdec_audio_stream.c swfdec/swfdec_audio_swf_stream.c swfdec/swfdec_bots.c swfdec/swfdec_bots.h swfdec/swfdec_buffer.c swfdec/swfdec_codec_gst.c swfdec/swfdec_codec_gst.h swfdec/swfdec_initialize.as swfdec/swfdec_initialize.h swfdec/swfdec_movie.c swfdec/swfdec_net_connection.c swfdec/swfdec_net_connection.h swfdec/swfdec_net_stream_as.c swfdec/swfdec_net_stream_audio.c swfdec/swfdec_net_stream_audio.h swfdec/swfdec_net_stream.c swfdec/swfdec_net_stream.h swfdec/swfdec_net_stream_video.c swfdec/swfdec_net_stream_video.h swfdec/swfdec_player.c swfdec/swfdec_rtmp_connection.c swfdec/swfdec_rtmp_connection.h swfdec/swfdec_rtmp_handshake.c swfdec/swfdec_rtmp_handshake.h swfdec/swfdec_rtmp_header.c swfdec/swfdec_rtmp_header.h swfdec/swfdec_rtmp_packet.c swfdec/swfdec_rtmp_packet.h swfdec/swfdec_rtmp_rpc.c swfdec/swfdec_rtmp_rpc.h swfdec/swfdec_rtmp_socket.c swfdec/swfdec_rtmp_socket.h swfdec/swfdec_rtmp_socket_rtmp.c swfdec/swfdec_rtmp_socket_rtmp.h swfdec/swfdec_rtmp_stream.c swfdec/swfdec_rtmp_stream.h swfdec/swfdec_sandbox.c swfdec/swfdec_sound.c swfdec/swfdec_sound_matrix.c swfdec/swfdec_swf_decoder.c swfdec/swfdec_utils.c swfdec/swfdec_utils.h swfdec/swfdec_video_decoder.c swfdec/swfdec_video_decoder_gst.c swfdec/swfdec_video_decoder.h swfdec/swfdec_video_decoder_screen.c swfdec/swfdec_video_decoder_vp6_alpha.c swfdec/swfdec_video_movie_as.c swfdec/swfdec_video_video_provider.c swfdec/swfdec_xml.c swfdec/swfdec_xml_node.c swfdec/swfdec_xml_node.h test/Makefile.am test/rtmp test/swfdec_test_buffer.c test/swfdec_test_initialize.as test/swfdec_test_initialize.h test/swfdec_test_socket.c test/swfdec_test_swfdec_socket.c tools/Makefile.am tools/rtmp-trace.c vivified/code
Benjamin Otte
company at kemper.freedesktop.org
Tue Dec 16 12:41:30 PST 2008
Rebased ref, commits from common ancestor:
commit 214acb83efe872502bd1a0cb343ede4d82b413af
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 15 18:00:57 2008 +0100
complain when data hasn't been properly read
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 71ccf5a..aea70b1 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -120,6 +120,9 @@ swfdec_rtmp_connection_handle_ping (SwfdecRtmpConnection *conn, SwfdecBuffer *bu
SWFDEC_FIXME ("handle ping type %u for target %u", type, target);
break;
}
+ if (swfdec_bits_left (&bits)) {
+ SWFDEC_FIXME ("bytes left in ping type %u", type);
+ }
}
static void
commit 3d819aded9429bd894b882b17b050f5411df16e1
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 15 16:55:21 2008 +0100
make seeking work properly
diff --git a/swfdec/swfdec_net_stream_video.c b/swfdec/swfdec_net_stream_video.c
index 9d94518..f7fe381 100644
--- a/swfdec/swfdec_net_stream_video.c
+++ b/swfdec/swfdec_net_stream_video.c
@@ -289,9 +289,16 @@ swfdec_net_stream_video_decode (SwfdecNetStreamVideo *video)
static void
swfdec_net_stream_video_start (SwfdecNetStreamVideo *video)
{
+ SwfdecRtmpPacket *packet = g_queue_peek_head (video->next);
+
+ g_assert (packet);
+ g_assert (!video->playing);
+
video->time = 0;
+ video->next->length += packet->header.timestamp;
video->playing = TRUE;
video->timeout.timestamp = SWFDEC_PLAYER (swfdec_gc_object_get_context (video))->priv->time;
+ video->timeout.timestamp -= SWFDEC_TICKS_PER_SECOND * packet->header.timestamp / 1000;
g_object_notify (G_OBJECT (video), "playing");
}
@@ -306,8 +313,9 @@ swfdec_net_stream_video_push (SwfdecNetStreamVideo *video,
packet = swfdec_rtmp_packet_new (header->channel, header->stream,
header->type, header->timestamp, buffer);
+ if (video->playing || !g_queue_is_empty (video->next))
+ video->next_length += header->timestamp;
g_queue_push_tail (video->next, packet);
- video->next_length += header->timestamp;
if (!video->playing && video->next_length >= video->buffer_time) {
swfdec_net_stream_video_start (video);
swfdec_net_stream_video_decode (video);
commit 5926a3a04a9c9f9e2fa504ab428fa91d01918000
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 15 16:55:05 2008 +0100
don't just free the queue data, clear the queues, too
diff --git a/swfdec/swfdec_audio_stream.c b/swfdec/swfdec_audio_stream.c
index 4b2d5fa..fd6b4c1 100644
--- a/swfdec/swfdec_audio_stream.c
+++ b/swfdec/swfdec_audio_stream.c
@@ -44,6 +44,7 @@ swfdec_audio_stream_clear (SwfdecAudio *audio)
}
g_queue_foreach (stream->queue, (GFunc) swfdec_buffer_unref, NULL);
g_queue_clear (stream->queue);
+ stream->queue_size = 0;
stream->done = FALSE;
stream->buffering = FALSE;
diff --git a/swfdec/swfdec_net_stream_audio.c b/swfdec/swfdec_net_stream_audio.c
index da1d8a1..5afdd7d 100644
--- a/swfdec/swfdec_net_stream_audio.c
+++ b/swfdec/swfdec_net_stream_audio.c
@@ -56,6 +56,7 @@ swfdec_net_stream_audio_clear (SwfdecAudio *audio)
if (g_queue_peek_tail (stream->queue) == NULL)
g_queue_pop_tail (stream->queue);
g_queue_foreach (stream->queue, (GFunc) swfdec_buffer_unref, NULL);
+ g_queue_clear (stream->queue);
SWFDEC_AUDIO_CLASS (swfdec_net_stream_audio_parent_class)->clear (audio);
}
commit 21c039ebca963b281bdba23448c9d1778043c5c7
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 15 16:54:02 2008 +0100
only add audio at the beginning, not whenever we get full/empty signals
Avoids 2 things: A/V sync and assertion failures
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index ab64135..85c9d9c 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -190,11 +190,8 @@ swfdec_net_stream_video_buffer_status (SwfdecNetStreamVideo *video, GParamSpec *
{
if (video->playing) {
swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Full);
- swfdec_audio_add (SWFDEC_AUDIO (stream->audio),
- SWFDEC_PLAYER (swfdec_gc_object_get_context (stream)));
} else {
swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Empty);
- swfdec_audio_remove (SWFDEC_AUDIO (stream->audio));
}
}
@@ -483,10 +480,12 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream->conn = conn;
stream->rpc = swfdec_rtmp_rpc_new (conn, SWFDEC_AS_RELAY (stream));
stream->video = swfdec_net_stream_video_new (SWFDEC_PLAYER (cx));
- stream->audio = swfdec_net_stream_audio_new (SWFDEC_PLAYER (cx));
g_object_ref (stream->video);
g_signal_connect (stream->video, "notify::playing",
G_CALLBACK (swfdec_net_stream_video_buffer_status), stream);
+ stream->audio = swfdec_net_stream_audio_new (SWFDEC_PLAYER (cx));
+ swfdec_audio_add (SWFDEC_AUDIO (stream->audio),
+ SWFDEC_PLAYER (swfdec_gc_object_get_context (stream)));
swfdec_as_context_get_time (cx, &stream->rpc->last_send);
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
}
commit 8d20d7c54b71f21a4130527fd61986f20fd05e57
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 15 11:59:21 2008 +0100
[OPTI] Don't create a super object for functions that suppresses it
diff --git a/swfdec/swfdec_as_super.c b/swfdec/swfdec_as_super.c
index a012b79..bbf4752 100644
--- a/swfdec/swfdec_as_super.c
+++ b/swfdec/swfdec_as_super.c
@@ -86,6 +86,8 @@ swfdec_as_super_new (SwfdecAsFrame *frame, SwfdecAsObject *thisp, SwfdecAsObject
if (frame->super != NULL)
return;
+ if (frame->script->flags & SWFDEC_SCRIPT_SUPPRESS_SUPER)
+ return;
context = thisp->context;
if (context->version <= 5)
return;
commit 7ce93e8349b88992f23880a9d461e1dbefbbdef8
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 15 10:47:28 2008 +0100
check the correct variable in return_if_fail
diff --git a/swfdec/swfdec_net_stream_video.c b/swfdec/swfdec_net_stream_video.c
index faf4a6f..9d94518 100644
--- a/swfdec/swfdec_net_stream_video.c
+++ b/swfdec/swfdec_net_stream_video.c
@@ -302,7 +302,7 @@ swfdec_net_stream_video_push (SwfdecNetStreamVideo *video,
SwfdecRtmpPacket *packet;
g_return_if_fail (SWFDEC_IS_NET_STREAM_VIDEO (video));
- g_return_if_fail (packet != NULL);
+ g_return_if_fail (buffer != NULL);
packet = swfdec_rtmp_packet_new (header->channel, header->stream,
header->type, header->timestamp, buffer);
commit 883f647ce176dcb234ceb6c5e4d3ee8a80520e76
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 14 21:43:56 2008 +0100
split in_error() from is_connected()
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 69034ab..71ccf5a 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -489,8 +489,9 @@ swfdec_rtmp_connection_send (SwfdecRtmpConnection *conn, SwfdecRtmpPacket *packe
* but that requires a g_queue_find_custom () and that's slow */
g_assert (packet->header.size == packet->buffer->length);
- if (!swfdec_rtmp_connection_is_connected (conn)) {
- SWFDEC_DEBUG ("ignoring send on closed connection");
+ if (!swfdec_rtmp_connection_is_connected (conn) ||
+ swfdec_rtmp_connection_in_error (conn)) {
+ SWFDEC_DEBUG ("ignoring send on broken connection");
return;
}
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index 4f285fa..1d8be0e 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -76,7 +76,8 @@ struct _SwfdecRtmpConnectionClass {
GType swfdec_rtmp_connection_get_type (void);
-#define swfdec_rtmp_connection_is_connected(conn) ((conn)->socket != NULL && (conn)->error == NULL)
+#define swfdec_rtmp_connection_is_connected(conn) ((conn)->socket != NULL)
+#define swfdec_rtmp_connection_in_error(conn) ((conn)->error != NULL)
void swfdec_rtmp_connection_connect (SwfdecRtmpConnection * conn,
const SwfdecURL * url);
void swfdec_rtmp_connection_close (SwfdecRtmpConnection * conn);
commit 41dd7becc52a391b55cabd020cba9340c2335279
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 14 21:25:50 2008 +0100
implement swfdec_net_stream_clear()
diff --git a/swfdec/swfdec_audio.c b/swfdec/swfdec_audio.c
index 0722feb..c2f5ebd 100644
--- a/swfdec/swfdec_audio.c
+++ b/swfdec/swfdec_audio.c
@@ -78,6 +78,12 @@ swfdec_audio_dispose (GObject *object)
}
static void
+swfdec_audio_do_clear (SwfdecAudio *audio)
+{
+ g_signal_emit (audio, signals[CHANGED], 0);
+}
+
+static void
swfdec_audio_class_init (SwfdecAudioClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -106,6 +112,8 @@ swfdec_audio_class_init (SwfdecAudioClass *klass)
G_TYPE_NONE, 0);
object_class->dispose = swfdec_audio_dispose;
+
+ klass->clear = swfdec_audio_do_clear;
}
static void
@@ -404,3 +412,20 @@ swfdec_audio_format_get_bytes_per_sample (SwfdecAudioFormat format)
return bps [format & 0x3];
}
+/**
+ * swfdec_audio_clear:
+ * @audio: the audio to clear
+ *
+ * Clears all caches of the given @audio output to prepare it for using with
+ * a different audio stream. This is useful i.e. after a seek.
+ **/
+void
+swfdec_audio_clear (SwfdecAudio *audio)
+{
+ SwfdecAudioClass *klass;
+
+ g_return_if_fail (SWFDEC_IS_AUDIO (audio));
+
+ klass = SWFDEC_AUDIO_GET_CLASS (audio);
+ klass->clear (audio);
+}
diff --git a/swfdec/swfdec_audio_internal.h b/swfdec/swfdec_audio_internal.h
index d225d71..21ac48f 100644
--- a/swfdec/swfdec_audio_internal.h
+++ b/swfdec/swfdec_audio_internal.h
@@ -48,6 +48,7 @@ struct _SwfdecAudio {
struct _SwfdecAudioClass {
GObjectClass object_class;
+ void (* clear) (SwfdecAudio * audio);
gsize (* iterate) (SwfdecAudio * audio,
gsize n_samples);
gsize (* render) (SwfdecAudio * audio,
@@ -59,6 +60,7 @@ struct _SwfdecAudioClass {
void swfdec_audio_add (SwfdecAudio * audio,
SwfdecPlayer * player);
void swfdec_audio_remove (SwfdecAudio * audio);
+void swfdec_audio_clear (SwfdecAudio * audio);
void swfdec_audio_set_actor (SwfdecAudio * audio,
SwfdecActor * actor);
void swfdec_audio_set_matrix (SwfdecAudio * audio,
diff --git a/swfdec/swfdec_audio_stream.c b/swfdec/swfdec_audio_stream.c
index 5eb0bfc..4b2d5fa 100644
--- a/swfdec/swfdec_audio_stream.c
+++ b/swfdec/swfdec_audio_stream.c
@@ -33,6 +33,24 @@
G_DEFINE_TYPE (SwfdecAudioStream, swfdec_audio_stream, SWFDEC_TYPE_AUDIO)
static void
+swfdec_audio_stream_clear (SwfdecAudio *audio)
+{
+ SwfdecAudioStream *stream = SWFDEC_AUDIO_STREAM (audio);
+
+ if (stream->decoder) {
+ /* FIXME: don't discard the decoder for smoother sounding seeks? */
+ g_object_unref (stream->decoder);
+ stream->decoder = NULL;
+ }
+ g_queue_foreach (stream->queue, (GFunc) swfdec_buffer_unref, NULL);
+ g_queue_clear (stream->queue);
+ stream->done = FALSE;
+ stream->buffering = FALSE;
+
+ SWFDEC_AUDIO_CLASS (swfdec_audio_stream_parent_class)->clear (audio);
+}
+
+static void
swfdec_audio_stream_dispose (GObject *object)
{
SwfdecAudioStream *stream = SWFDEC_AUDIO_STREAM (object);
@@ -178,6 +196,7 @@ swfdec_audio_stream_class_init (SwfdecAudioStreamClass *klass)
object_class->dispose = swfdec_audio_stream_dispose;
+ audio_class->clear = swfdec_audio_stream_clear;
audio_class->iterate = swfdec_audio_stream_iterate;
audio_class->render = swfdec_audio_stream_render;
}
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 4f7599c..ab64135 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -149,9 +149,12 @@ swfdec_net_stream_rtmp_stream_flush (SwfdecRtmpStream *rtmp_stream)
}
static void
-swfdec_net_stream_rtmp_stream_clear (SwfdecRtmpStream *stream)
+swfdec_net_stream_rtmp_stream_clear (SwfdecRtmpStream *rtmp_stream)
{
- SWFDEC_FIXME ("implement");
+ SwfdecNetStream *stream = SWFDEC_NET_STREAM (rtmp_stream);
+
+ swfdec_net_stream_video_clear (stream->video);
+ swfdec_audio_clear (SWFDEC_AUDIO (stream->audio));
}
static void
@@ -187,8 +190,11 @@ swfdec_net_stream_video_buffer_status (SwfdecNetStreamVideo *video, GParamSpec *
{
if (video->playing) {
swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Full);
+ swfdec_audio_add (SWFDEC_AUDIO (stream->audio),
+ SWFDEC_PLAYER (swfdec_gc_object_get_context (stream)));
} else {
swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Empty);
+ swfdec_audio_remove (SWFDEC_AUDIO (stream->audio));
}
}
diff --git a/swfdec/swfdec_net_stream_audio.c b/swfdec/swfdec_net_stream_audio.c
index a28f4ea..da1d8a1 100644
--- a/swfdec/swfdec_net_stream_audio.c
+++ b/swfdec/swfdec_net_stream_audio.c
@@ -47,6 +47,19 @@ swfdec_net_stream_audio_dispose (GObject *object)
G_OBJECT_CLASS (swfdec_net_stream_audio_parent_class)->dispose (object);
}
+static void
+swfdec_net_stream_audio_clear (SwfdecAudio *audio)
+{
+ SwfdecNetStreamAudio *stream = SWFDEC_NET_STREAM_AUDIO (audio);
+
+ /* pop eventual NULL buffer indicating end of data */
+ if (g_queue_peek_tail (stream->queue) == NULL)
+ g_queue_pop_tail (stream->queue);
+ g_queue_foreach (stream->queue, (GFunc) swfdec_buffer_unref, NULL);
+
+ SWFDEC_AUDIO_CLASS (swfdec_net_stream_audio_parent_class)->clear (audio);
+}
+
static SwfdecBuffer *
swfdec_net_stream_audio_pull (SwfdecAudioStream *audio)
{
@@ -78,10 +91,13 @@ static void
swfdec_net_stream_audio_class_init (SwfdecNetStreamAudioClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ SwfdecAudioClass *audio_class = SWFDEC_AUDIO_CLASS (klass);
SwfdecAudioStreamClass *stream_class = SWFDEC_AUDIO_STREAM_CLASS (klass);
object_class->dispose = swfdec_net_stream_audio_dispose;
+ audio_class->clear = swfdec_net_stream_audio_clear;
+
stream_class->pull = swfdec_net_stream_audio_pull;
}
@@ -113,5 +129,11 @@ swfdec_net_stream_audio_push (SwfdecNetStreamAudio *audio, SwfdecBuffer *buffer)
swfdec_buffer_unref (buffer);
return;
};
+ if (!g_queue_is_empty (audio->queue) && g_queue_peek_tail (audio->queue) == NULL) {
+ SWFDEC_ERROR ("pushing data onto an audio stream that is done. Ignoring.");
+ if (buffer)
+ swfdec_buffer_unref (buffer);
+ return;
+ }
g_queue_push_tail (audio->queue, buffer);
}
diff --git a/swfdec/swfdec_net_stream_video.c b/swfdec/swfdec_net_stream_video.c
index ccfddde..faf4a6f 100644
--- a/swfdec/swfdec_net_stream_video.c
+++ b/swfdec/swfdec_net_stream_video.c
@@ -116,6 +116,7 @@ swfdec_net_stream_video_dispose (GObject *object)
if (video->timeout.callback) {
swfdec_player_remove_timeout (SWFDEC_PLAYER (swfdec_gc_object_get_context (video)),
&video->timeout);
+ video->timeout.callback = NULL;
}
G_OBJECT_CLASS (swfdec_net_stream_video_parent_class)->dispose (object);
@@ -153,6 +154,24 @@ swfdec_net_stream_video_new (SwfdecPlayer *player)
return ret;
}
+void
+swfdec_net_stream_video_clear (SwfdecNetStreamVideo *video)
+{
+ g_return_if_fail (SWFDEC_IS_NET_STREAM_VIDEO (video));
+
+ video->time = 0;
+ g_queue_foreach (video->next, (GFunc) swfdec_rtmp_packet_free, NULL);
+ g_queue_clear (video->next);
+ video->next_length = 0;
+ video->playing = FALSE;
+ if (video->timeout.callback) {
+ swfdec_player_remove_timeout (SWFDEC_PLAYER (swfdec_gc_object_get_context (video)),
+ &video->timeout);
+ video->timeout.callback = NULL;
+ }
+ /* FIXME: clear decoder, too? currently it's needed for getting the current image */
+}
+
static void
swfdec_net_stream_video_decode_one (SwfdecNetStreamVideo *video, SwfdecBuffer *buffer)
{
diff --git a/swfdec/swfdec_net_stream_video.h b/swfdec/swfdec_net_stream_video.h
index 2aa5145..1e7cdfd 100644
--- a/swfdec/swfdec_net_stream_video.h
+++ b/swfdec/swfdec_net_stream_video.h
@@ -58,6 +58,7 @@ GType swfdec_net_stream_video_get_type (void);
SwfdecNetStreamVideo * swfdec_net_stream_video_new (SwfdecPlayer * player);
+void swfdec_net_stream_video_clear (SwfdecNetStreamVideo * video);
void swfdec_net_stream_video_push (SwfdecNetStreamVideo * video,
const SwfdecRtmpHeader *header,
SwfdecBuffer * buffer);
commit a9bbc0a515517498a7defcfb78de2db3667cd635
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 14 19:13:36 2008 +0100
ignore too small buffers
diff --git a/swfdec/swfdec_net_stream_audio.c b/swfdec/swfdec_net_stream_audio.c
index 893e728..a28f4ea 100644
--- a/swfdec/swfdec_net_stream_audio.c
+++ b/swfdec/swfdec_net_stream_audio.c
@@ -108,5 +108,10 @@ swfdec_net_stream_audio_push (SwfdecNetStreamAudio *audio, SwfdecBuffer *buffer)
{
g_return_if_fail (SWFDEC_IS_NET_STREAM_AUDIO (audio));
+ if (buffer && buffer->length < 2) {
+ SWFDEC_WARNING ("buffer too small, ignoring");
+ swfdec_buffer_unref (buffer);
+ return;
+ };
g_queue_push_tail (audio->queue, buffer);
}
commit 0dab90b5351f5bba533671537426f582149abc89
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 14 18:00:20 2008 +0100
set NetConnection.isConnected and NetConnection.uri after connecting
diff --git a/swfdec/swfdec_as_strings.c b/swfdec/swfdec_as_strings.c
index 2385981..a03ce40 100644
--- a/swfdec/swfdec_as_strings.c
+++ b/swfdec/swfdec_as_strings.c
@@ -547,6 +547,8 @@ const SwfdecAsConstantStringValue swfdec_as_strings[] = {
SWFDEC_AS_CONSTANT_STRING ("onResult")
SWFDEC_AS_CONSTANT_STRING ("pageUrl")
SWFDEC_AS_CONSTANT_STRING ("videoFunction")
+ SWFDEC_AS_CONSTANT_STRING ("isConnected")
+ SWFDEC_AS_CONSTANT_STRING ("uri")
/* add more here */
{ 0, 0, "" }
};
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index e284208..69034ab 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -25,6 +25,7 @@
#include <string.h>
+#include "swfdec_as_internal.h"
#include "swfdec_as_strings.h"
#include "swfdec_bots.h"
#include "swfdec_debug.h"
@@ -399,6 +400,7 @@ swfdec_rtmp_connection_close (SwfdecRtmpConnection *conn)
conn->socket = NULL;
swfdec_url_free (conn->url);
conn->url = NULL;
+ swfdec_rtmp_connection_set_connected (conn, NULL);
}
void
@@ -487,6 +489,11 @@ swfdec_rtmp_connection_send (SwfdecRtmpConnection *conn, SwfdecRtmpPacket *packe
* but that requires a g_queue_find_custom () and that's slow */
g_assert (packet->header.size == packet->buffer->length);
+ if (!swfdec_rtmp_connection_is_connected (conn)) {
+ SWFDEC_DEBUG ("ignoring send on closed connection");
+ return;
+ }
+
packet->buffer->length = 0;
send = g_queue_is_empty (conn->packets);
g_queue_push_head (conn->packets, packet);
@@ -495,3 +502,29 @@ swfdec_rtmp_connection_send (SwfdecRtmpConnection *conn, SwfdecRtmpPacket *packe
if (send)
swfdec_rtmp_socket_send (conn->socket);
}
+
+void
+swfdec_rtmp_connection_set_connected (SwfdecRtmpConnection *conn,
+ const char *url)
+{
+ SwfdecAsObject *object;
+ SwfdecAsValue *val, tmp;
+
+ g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
+
+ object = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (conn));
+ val = swfdec_as_object_peek_variable (object, SWFDEC_AS_STR_isConnected);
+ if (val) {
+ SWFDEC_AS_VALUE_SET_BOOLEAN (val, url != NULL);
+ } else {
+ SWFDEC_FIXME ("something weird happens when isConnected was deleted");
+ }
+ /* FIXME: should not fail if variable exists but is constant */
+ if (url) {
+ SWFDEC_AS_VALUE_SET_STRING (&tmp, url);
+ } else {
+ SWFDEC_AS_VALUE_SET_UNDEFINED (&tmp);
+ }
+ swfdec_as_object_set_variable (object, SWFDEC_AS_STR_uri, &tmp);
+}
+
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index 38d916d..4f285fa 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -76,7 +76,7 @@ struct _SwfdecRtmpConnectionClass {
GType swfdec_rtmp_connection_get_type (void);
-#define swfdec_rtmp_connection_is_connected(conn) ((conn)->socket != NULL)
+#define swfdec_rtmp_connection_is_connected(conn) ((conn)->socket != NULL && (conn)->error == NULL)
void swfdec_rtmp_connection_connect (SwfdecRtmpConnection * conn,
const SwfdecURL * url);
void swfdec_rtmp_connection_close (SwfdecRtmpConnection * conn);
@@ -89,6 +89,8 @@ void swfdec_rtmp_connection_queue_control_packet
(SwfdecRtmpConnection * conn,
SwfdecRtmpPacket * packet);
+void swfdec_rtmp_connection_set_connected (SwfdecRtmpConnection * conn,
+ const char * url);
void swfdec_rtmp_connection_error (SwfdecRtmpConnection * conn,
const char * error,
...) G_GNUC_PRINTF (2, 3);
diff --git a/swfdec/swfdec_rtmp_socket_rtmp.c b/swfdec/swfdec_rtmp_socket_rtmp.c
index 2fdedb3..7366ff7 100644
--- a/swfdec/swfdec_rtmp_socket_rtmp.c
+++ b/swfdec/swfdec_rtmp_socket_rtmp.c
@@ -63,8 +63,12 @@ static void
swfdec_rtmp_socket_rtmp_stream_target_open (SwfdecStreamTarget *target, SwfdecStream *stream)
{
SwfdecRtmpSocketRtmp *rtmp = SWFDEC_RTMP_SOCKET_RTMP (target);
+ SwfdecRtmpSocket *sock = SWFDEC_RTMP_SOCKET (target);
- rtmp->next = swfdec_rtmp_socket_next_buffer (SWFDEC_RTMP_SOCKET (target));
+ swfdec_rtmp_connection_set_connected (sock->conn,
+ swfdec_as_context_get_string (swfdec_gc_object_get_context (sock->conn),
+ swfdec_url_get_url (sock->conn->url)));
+ rtmp->next = swfdec_rtmp_socket_next_buffer (sock);
swfdec_rtmp_socket_rtmp_do_send (rtmp);
}
commit 2cdc5065158df907df68fa30e413769309c80dbd
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 14 18:00:13 2008 +0100
implement setBufferTime
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index b4cd38d..4f7599c 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -262,12 +262,45 @@ swfdec_net_stream_send (SwfdecAsContext *cx, SwfdecAsObject *object,
SWFDEC_STUB ("NetStream.send");
}
+static void
+swfdec_net_stream_send_buffer_time (SwfdecNetStream *stream, guint buffer_time)
+{
+ SwfdecRtmpPacket *packet;
+ SwfdecBots *bots;
+ SwfdecBuffer *buffer;
+
+ bots = swfdec_bots_new ();
+ swfdec_bots_put_bu16 (bots, 3);
+ swfdec_bots_put_bu32 (bots, stream->stream);
+ swfdec_bots_put_bu32 (bots, buffer_time);
+ buffer = swfdec_bots_close (bots);
+
+ packet = swfdec_rtmp_packet_new (2, 0, SWFDEC_RTMP_PACKET_PING, 0, buffer);
+ swfdec_buffer_unref (buffer);
+ swfdec_rtmp_connection_queue_control_packet (stream->conn, packet);
+}
+
SWFDEC_AS_NATIVE (2101, 4, swfdec_net_stream_setBufferTime)
void
swfdec_net_stream_setBufferTime (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.setBufferTime");
+ SwfdecNetStream *stream;
+ double d;
+ int i;
+
+ SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "n", &d);
+
+ if (d < 0) {
+ i = 0;
+ } else {
+ i = swfdec_as_double_to_integer (d * 1000);
+ }
+
+ if (stream->video->buffer_time != (guint) i) {
+ stream->video->buffer_time = i;
+ swfdec_net_stream_send_buffer_time (stream, i);
+ }
}
SWFDEC_AS_NATIVE (2101, 5, swfdec_net_stream_get_checkPolicyFile)
@@ -452,24 +485,6 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
}
-static void
-swfdec_net_stream_send_buffer_time (SwfdecNetStream *stream, guint buffer_time)
-{
- SwfdecRtmpPacket *packet;
- SwfdecBots *bots;
- SwfdecBuffer *buffer;
-
- bots = swfdec_bots_new ();
- swfdec_bots_put_bu16 (bots, 3);
- swfdec_bots_put_bu32 (bots, stream->stream);
- swfdec_bots_put_bu32 (bots, buffer_time);
- buffer = swfdec_bots_close (bots);
-
- packet = swfdec_rtmp_packet_new (2, 0, SWFDEC_RTMP_PACKET_PING, 0, buffer);
- swfdec_buffer_unref (buffer);
- swfdec_rtmp_connection_queue_control_packet (stream->conn, packet);
-}
-
SWFDEC_AS_NATIVE (2101, 201, swfdec_net_stream_onCreate)
void
swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
commit 07bc888c3c1aaef21c3aa8f024cdb7434c73967a
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 14 17:59:49 2008 +0100
handle packet size changes
diff --git a/tools/rtmp-trace.c b/tools/rtmp-trace.c
index b271c0d..b7cbe28 100644
--- a/tools/rtmp-trace.c
+++ b/tools/rtmp-trace.c
@@ -220,7 +220,7 @@ static gboolean
process_one_packet (GPtrArray *lines, const char *type, RtmpConn *conn)
{
SwfdecRtmpPacket *packet;
- SwfdecRtmpHeader header = { 0, };
+ SwfdecRtmpHeader header;
SwfdecBuffer *buffer;
SwfdecBits bits;
gsize header_size, i, remaining;
@@ -242,9 +242,8 @@ process_one_packet (GPtrArray *lines, const char *type, RtmpConn *conn)
if (packet == NULL) {
packet = swfdec_rtmp_packet_new_empty ();
g_hash_table_insert (conn->pending, GUINT_TO_POINTER (i), packet);
- } else {
- swfdec_rtmp_header_copy (&header, &packet->header);
}
+ swfdec_rtmp_header_copy (&header, &packet->header);
swfdec_rtmp_header_read (&header, &bits);
swfdec_buffer_unref (buffer);
@@ -272,6 +271,15 @@ process_one_packet (GPtrArray *lines, const char *type, RtmpConn *conn)
buffer = swfdec_buffer_queue_pull (conn->queue, header_size + remaining);
g_assert (buffer);
write_line (lines, type, buffer);
+
+ /* adjust packet size if this was a packet size adjustment packet */
+ if (header.type == SWFDEC_RTMP_PACKET_SIZE) {
+ swfdec_bits_init (&bits, buffer);
+ swfdec_bits_skip_bytes (&bits, header_size);
+ conn->packet_size = swfdec_bits_get_bu32 (&bits);
+ }
+
+ swfdec_buffer_unref (buffer);
return TRUE;
}
commit 2fedeb94a5758ae92908f9384eaf8c81fdcbdb48
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 20:59:37 2008 +0100
refactor
diff --git a/tools/rtmp-trace.c b/tools/rtmp-trace.c
index 26e5b18..b271c0d 100644
--- a/tools/rtmp-trace.c
+++ b/tools/rtmp-trace.c
@@ -155,12 +155,36 @@ swfdec_buffer_from_string (const char *s)
return buffer;
}
+typedef struct _RtmpConn {
+ SwfdecBufferQueue * queue;
+ GHashTable * pending;
+ guint packet_size;
+} RtmpConn;
+
+static RtmpConn *
+rtmp_conn_new (void)
+{
+ RtmpConn *conn = g_slice_new (RtmpConn);
+
+ conn->queue = swfdec_buffer_queue_new ();
+ conn->pending = g_hash_table_new (g_direct_hash, g_direct_equal);
+ conn->packet_size = 128;
+
+ return conn;
+}
+
+static void
+rtmp_conn_free (RtmpConn *conn)
+{
+ swfdec_buffer_queue_unref (conn->queue);
+ g_hash_table_destroy (conn->pending);
+ g_slice_free (RtmpConn, conn);
+}
+
typedef struct _RtmpState {
guint handshake;
- SwfdecBufferQueue * send;
- GHashTable * send_pending;
- SwfdecBufferQueue * recv;
- GHashTable * recv_pending;
+ RtmpConn * send;
+ RtmpConn * recv;
} RtmpState;
static RtmpState *
@@ -169,10 +193,8 @@ rtmp_state_new (void)
RtmpState *state = g_slice_new0 (RtmpState);
state->handshake = 3;
- state->send = swfdec_buffer_queue_new ();
- state->send_pending = g_hash_table_new (g_direct_hash, g_direct_equal);
- state->recv = swfdec_buffer_queue_new ();
- state->recv_pending = g_hash_table_new (g_direct_hash, g_direct_equal);
+ state->send = rtmp_conn_new ();
+ state->recv = rtmp_conn_new ();
return state;
}
@@ -180,10 +202,7 @@ rtmp_state_new (void)
static void
rtmp_state_free (RtmpState *state)
{
- swfdec_buffer_queue_unref (state->send);
- g_hash_table_destroy (state->send_pending);
- swfdec_buffer_queue_unref (state->recv);
- g_hash_table_destroy (state->recv_pending);
+ rtmp_conn_free (state->recv);
g_slice_free (RtmpState, state);
}
@@ -198,8 +217,7 @@ write_line (GPtrArray *lines, const char *type, SwfdecBuffer *buffer)
}
static gboolean
-process_one_packet (GPtrArray *lines, const char *type,
- GHashTable *lookup, SwfdecBufferQueue *queue, guint packet_size)
+process_one_packet (GPtrArray *lines, const char *type, RtmpConn *conn)
{
SwfdecRtmpPacket *packet;
SwfdecRtmpHeader header = { 0, };
@@ -208,22 +226,22 @@ process_one_packet (GPtrArray *lines, const char *type,
gsize header_size, i, remaining;
/* determine size of header */
- buffer = swfdec_buffer_queue_peek (queue, 1);
+ buffer = swfdec_buffer_queue_peek (conn->queue, 1);
if (buffer == NULL)
return FALSE;
header_size = swfdec_rtmp_header_peek_size (buffer->data[0]);
swfdec_buffer_unref (buffer);
/* read header */
- buffer = swfdec_buffer_queue_peek (queue, header_size);
+ buffer = swfdec_buffer_queue_peek (conn->queue, header_size);
if (buffer == NULL)
return FALSE;
swfdec_bits_init (&bits, buffer);
i = swfdec_rtmp_header_peek_channel (&bits);
- packet = g_hash_table_lookup (lookup, GUINT_TO_POINTER (i));
+ packet = g_hash_table_lookup (conn->pending, GUINT_TO_POINTER (i));
if (packet == NULL) {
packet = swfdec_rtmp_packet_new_empty ();
- g_hash_table_insert (lookup, GUINT_TO_POINTER (i), packet);
+ g_hash_table_insert (conn->pending, GUINT_TO_POINTER (i), packet);
} else {
swfdec_rtmp_header_copy (&header, &packet->header);
}
@@ -240,18 +258,18 @@ process_one_packet (GPtrArray *lines, const char *type,
} else {
remaining = header.size;
}
- if (header_size + MIN (packet_size, remaining) > swfdec_buffer_queue_get_depth (queue))
+ if (header_size + MIN (conn->packet_size, remaining) > swfdec_buffer_queue_get_depth (conn->queue))
return FALSE;
swfdec_rtmp_header_copy (&packet->header, &header);
- if (remaining <= packet_size) {
+ if (remaining <= conn->packet_size) {
packet->buffer = GSIZE_TO_POINTER (0);
} else {
- packet->buffer = GSIZE_TO_POINTER (remaining - packet_size);
- remaining = packet_size;
+ packet->buffer = GSIZE_TO_POINTER (remaining - conn->packet_size);
+ remaining = conn->packet_size;
}
- buffer = swfdec_buffer_queue_pull (queue, header_size + remaining);
+ buffer = swfdec_buffer_queue_pull (conn->queue, header_size + remaining);
g_assert (buffer);
write_line (lines, type, buffer);
return TRUE;
@@ -260,13 +278,13 @@ process_one_packet (GPtrArray *lines, const char *type,
static void
rtmp_process_send (RtmpState *state, GPtrArray *lines, SwfdecBuffer *buffer)
{
- swfdec_buffer_queue_push (state->send, buffer);
+ swfdec_buffer_queue_push (state->send->queue, buffer);
switch (state->handshake) {
case 0:
break;
case 1:
- buffer = swfdec_buffer_queue_pull (state->send, 1536);
+ buffer = swfdec_buffer_queue_pull (state->send->queue, 1536);
if (buffer == NULL)
return;
write_line (lines, "send", buffer);
@@ -276,7 +294,7 @@ rtmp_process_send (RtmpState *state, GPtrArray *lines, SwfdecBuffer *buffer)
g_printerr ("sent data when waiting for RTMP handshake reply?");
return;
case 3:
- buffer = swfdec_buffer_queue_pull (state->send, 1537);
+ buffer = swfdec_buffer_queue_pull (state->send->queue, 1537);
if (buffer) {
write_line (lines, "send", buffer);
state->handshake--;
@@ -287,14 +305,13 @@ rtmp_process_send (RtmpState *state, GPtrArray *lines, SwfdecBuffer *buffer)
break;
}
- while (process_one_packet (lines, "send", state->send_pending, state->send, 128))
- ;
+ while (process_one_packet (lines, "send", state->send));
}
static void
rtmp_process_recv (RtmpState *state, GPtrArray *lines, SwfdecBuffer *buffer)
{
- swfdec_buffer_queue_push (state->recv, buffer);
+ swfdec_buffer_queue_push (state->recv->queue, buffer);
switch (state->handshake) {
case 0:
@@ -303,7 +320,7 @@ rtmp_process_recv (RtmpState *state, GPtrArray *lines, SwfdecBuffer *buffer)
g_printerr ("received data when waiting for RTMP handshake data?");
return;
case 2:
- buffer = swfdec_buffer_queue_pull (state->recv, 1536 * 2 + 1);
+ buffer = swfdec_buffer_queue_pull (state->recv->queue, 1536 * 2 + 1);
if (buffer) {
write_line (lines, "recv", buffer);
state->handshake--;
@@ -317,8 +334,7 @@ rtmp_process_recv (RtmpState *state, GPtrArray *lines, SwfdecBuffer *buffer)
break;
}
- while (process_one_packet (lines, "recv", state->recv_pending, state->recv, 128))
- ;
+ while (process_one_packet (lines, "recv", state->recv));
}
static char **
commit 2be24efbc8e59d295aa6fd2ca9d5db14c801cfe4
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 20:41:25 2008 +0100
rewrite testsuite using this method
diff --git a/test/rtmp/default.stas b/test/rtmp/default.stas
index a2ff0e6..98b2925 100644
--- a/test/rtmp/default.stas
+++ b/test/rtmp/default.stas
@@ -39,12 +39,8 @@ Socket.prototype.nextCommand = function (required_command) {
};
Socket.prototype.onData = function (data) {
- if (this.commands[this.commands.length - 1].indexOf ("send ") == 0)
- this.commands[this.commands.length - 1] += data;
- else
- this.commands.push ("send " + data);
- if (this.buffer.find (10) <= this.commands[this.commands.length - 1].length)
- this.nextCommand ("send");
+ this.commands.push ("send " + data);
+ this.nextCommand ("send");
this.do_send ();
};
@@ -52,10 +48,7 @@ Socket.prototype.do_send = function () {
tmp = this.nextCommand ("recv");
while (tmp) {
this.send (tmp.data);
- if (this.commands[this.commands.length - 1].indexOf ("recv ") == 0)
- this.commands[this.commands.length - 1] += tmp.data;
- else
- this.commands.push ("recv " + tmp.data);
+ this.commands.push ("recv " + tmp.data);
tmp = this.nextCommand ("recv");
}
};
diff --git a/test/rtmp/default.sts b/test/rtmp/default.sts
index 2488033..d0c902e 100644
Binary files a/test/rtmp/default.sts and b/test/rtmp/default.sts differ
diff --git a/test/rtmp/hello-world-6.swf.dump b/test/rtmp/hello-world-6.swf.dump
index 4cb10af..0c9175d 100644
--- a/test/rtmp/hello-world-6.swf.dump
+++ b/test/rtmp/hello-world-6.swf.dump
@@ -1,6 +1,11 @@
send \3\0\0\0\0\0\0\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4
recv \3\2-\335\27\0\0\0\0005\323\250\267\22R\30 at f\t\213\3628\205\204\360\227\265\377\265\234\272\235\366\257Y\372\313]\323X\1=p\314#\310L\304\357\254\231\335\375\3709\261R\236\322M\200o\341\224Gl\314\336\337\7\1\22P\0265\37<\331\362l\203\260 \330$\377g\347mv\20L\1\247\276R\3W\226\252\340\271-\252em\373y\250\332\204\232p\355\314b\222\314\337\303\n\342\250w\rBu>\311c\210B\25;\4\337$\250\202d|\331\235]\225\302p\250\0^\355v\237\311\262#\271/\210\26\\\274*:\271\37\275tx\n\33\21\241\256t\346\340\'\367^\374\2142\0170\242\256\362w\362\273\7>\326\253\0374\275\247\6\215\275\354\323@\345\331]\212\36\264t\204\332\332\251\21\310\205Z\263\6\276\230o\322\260\207$\272\274*\321\7%\v#\271\326R\261\331#\26i\365\222\363\225\32\342t\221+\245#\260{O\251\343\300\225g\205\t\242\10\240\16VX\327\222Y\1z\261jcd\267\355\330\245\337\27\225\332\233X\311S\21\207\254\334\260\317\334c\345\210\331\377\237Kc\312\246\362\346pE\211\361\365\324Ni9\3\241\204\334\256y\312 \366J\314\352I\177C\331!\337\217To\0063\27\342,m\367,\34\332\342..\262\324\n\272\r\333\7\305F\36\251w\4\235 \343J}\262j\334\210\340\372\370\346\253\306\24I\f\355\245q\2234V9\352\32\0107H\r\334\361\250\373\372+`\246\333\336\2217\301\351\332\5\252\321NJT\327k\236^\347\220\314w\373\30\335\205\0\366\324/_\345\361\313j\360%\353.[\3204\366\27\2441\325\342\356\272C{x(3\315\202\273@\20\35ze\333\337\310\217\255\257\373{`1Qpgh.\273h\303\v\246\33^J\33\264\206\262\246\235X\251p\251SVe\6\332M2#}\244\253\r`N\322\220s\23\337\372\343\344*j\204\302\37T\267=\277\303\270 \274e\335wu\261\272\244\212l9\214j\306\374\213\347\274tM\361\233\303z\221\261\243\26\215A\337U\0355\321\231\36\300\352t)\4\342\353\255\320\346\274\332d\324\272\325\276\334^6;\224\2057\4\266\236\5g4x\343\356`\16!\233\316\244\'\"\267\375\274\376\1\264\vf\370\372\371\'\332\352\5\362h!\224\2\210\316\335Ee\227j\206\265A\201\206z\331\257\2\245\312T\335O\305\1\242\347\351DO\334\217\330#\214^^s\225\221\312\205Y\'\f#\360\350\355\365\376\214\7\320oITP\35\345\"j\263\331\332\3\317B\201:\243\203\325\364K`\244\270i\2236\20|r\35\352\344\t\250\344\340ZH\241/\221;a\302Q\t>\247\34C\276\\\235\272\332!i\271*\f8\221\f^\214\314\367\361}\355.*\n\335X\242\2141\17\300b\334\340\344\7\342\270\335=\206!\32\275\5@\377?\311\341\7\335M\363\366g\246\3003\35&\314P6\231;N\2502\342\343\27\253\334V\6\1775\332\373\317\21e(\4\365\375\363.\366eW\36\313\213\2N\364\240\252\31\261\231\274\230Y\354\255\253w\240\302\2240\241\362V\tZG\331$\231\327M\253O\364\377\255\4\3256\2\301G\317\235\257v8\244\356k\3726\343\t\317\226R\351\202\303c\322Y\31}\27\tX\347\202k\253\321>\31\272\271`\203(k\3\'|\261\35-\204\260\f-\214\220u\236@\273\2473\324\376\235\346\320\32xv\374#\23q\246\312\331AR,\233\351U\33\375\346S\222\36\226\346\1\330\363\r_3\236\311;\313\373u\20\312\34\264\335\253\232_\375\25\207\34$\177i\373\301\311\r\273\356\245&\22\340\311 6\245\310ol\340\4\'\221A\216\34?\254<\241b\37\265\354\354Z\275e\251\357\363\325hd\236\r\260_b\202\37\251\224\274\375\267\22\272\260\306^v\370\f\224ji\244\t<\231\255\266\275\36\373\352\251\364\336PK\263\324\366\307dv\36\0014\353_Q\202\33fMem0\2\261 vA\37Y\304C\351\231\3266\347\347\3050\2735\306\247F\313\262\276\7\304h\352^\333\256}\242Ax-\350\3\375\263\201\327f \213\276\1\3610\\\344\210Y7C\220{\270\324R\200\306-\306\246X\337\264\240\371\363\307,(O\226\26^g\274q\341\242Z\20\37\7\17\232\221_$\250i\336+O\231\37\233\233o4\352\360\r\213\316gS\206\20\221O\364M\254x\242\257\207\1M\0042\353Q\6\265\313*\213\207\332=Y~\226\375\313~\312yx\261\37\354\v\271\2nGL\355 \7\271\212\34\"T\251\25\246\3174@%\244\30\24E\210\205\312\223C\"\220\243,\301tCj\f\16\2449\2\362\232:t\225\305q\300q.g\351\v\307\345N\210N\260\21z\275\305_\17\236\202A\3251-[0\'\217\342\235\222\260\34?\232n\327{&N{\206\214\16\224\343\355\270\n)\374X\227l\343\375\342*\305/\222\34\207X\342K\26\251\304\235&NzF\272\274\347\0202\355\343\25\3237\372\250\355\7OT\313\20j\240\3wu\263\261\246\375n\225g\262\210!\330\376\260+\374\216\313Q\344u\243\362\325\324\242\0045\266\2339\227Z\232<\327R\324\213b\270\t\0319\224\3724\261\227\233\360\313\234\313\35MU\310@\240\22\03233\352\326\266\307au_E-\275\223\371w\221\317\0200\343\353\23089x\25\247\266\203l\334p\321R\330\221\213\364\274}\206\366\10jB\241\274\305\312\244\4\374\t\"\tAmq\3652\317k\6\7\245\241\310\201\224v\r\177\247\0\352\310\25v\23\217/r\345(\305\200I@\223\227]\246|\214\f\356!\0\0\0\0\0\0\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4
send \2-\335\27\0\0\0\0005\323\250\267\22R\30 at f\t\213\3628\205\204\360\227\265\377\265\234\272\235\366\257Y\372\313]\323X\1=p\314#\310L\304\357\254\231\335\375\3709\261R\236\322M\200o\341\224Gl\314\336\337\7\1\22P\0265\37<\331\362l\203\260 \330$\377g\347mv\20L\1\247\276R\3W\226\252\340\271-\252em\373y\250\332\204\232p\355\314b\222\314\337\303\n\342\250w\rBu>\311c\210B\25;\4\337$\250\202d|\331\235]\225\302p\250\0^\355v\237\311\262#\271/\210\26\\\274*:\271\37\275tx\n\33\21\241\256t\346\340\'\367^\374\2142\0170\242\256\362w\362\273\7>\326\253\0374\275\247\6\215\275\354\323@\345\331]\212\36\264t\204\332\332\251\21\310\205Z\263\6\276\230o\322\260\207$\272\274*\321\7%\v#\271\326R\261\331#\26i\365\222\363\225\32\342t\221+\245#\260{O\251\343\300\225g\205\t\242\10\240\16VX\327\222Y\1z\261jcd\267\355\330\245\337\27\225\332\233X\311S\21\207\254\334\260\317\334c\345\210\331\377\237Kc\312\246\362\346pE\211\361\365\324Ni9\3\241\204\334\256y\312 \366J\314\352I\177C\331!\337\217To\0063\27\342,m\367,\34\332\342..\262\324\n\272\r\333\7\305F\36\251w\4\235 \343J}\262j\334\210\340\372\370\346\253\306\24I\f\355\245q\2234V9\352\32\0107H\r\334\361\250\373\372+`\246\333\336\2217\301\351\332\5\252\321NJT\327k\236^\347\220\314w\373\30\335\205\0\366\324/_\345\361\313j\360%\353.[\3204\366\27\2441\325\342\356\272C{x(3\315\202\273@\20\35ze\333\337\310\217\255\257\373{`1Qpgh.\273h\303\v\246\33^J\33\264\206\262\246\235X\251p\251SVe\6\332M2#}\244\253\r`N\322\220s\23\337\372\343\344*j\204\302\37T\267=\277\303\270 \274e\335wu\261\272\244\212l9\214j\306\374\213\347\274tM\361\233\303z\221\261\243\26\215A\337U\0355\321\231\36\300\352t)\4\342\353\255\320\346\274\332d\324\272\325\276\334^6;\224\2057\4\266\236\5g4x\343\356`\16!\233\316\244\'\"\267\375\274\376\1\264\vf\370\372\371\'\332\352\5\362h!\224\2\210\316\335Ee\227j\206\265A\201\206z\331\257\2\245\312T\335O\305\1\242\347\351DO\334\217\330#\214^^s\225\221\312\205Y\'\f#\360\350\355\365\376\214\7\320oITP\35\345\"j\263\331\332\3\317B\201:\243\203\325\364K`\244\270i\2236\20|r\35\352\344\t\250\344\340ZH\241/\221;a\302Q\t>\247\34C\276\\\235\272\332!i\271*\f8\221\f^\214\314\367\361}\355.*\n\335X\242\2141\17\300b\334\340\344\7\342\270\335=\206!\32\275\5@\377?\311\341\7\335M\363\366g\246\3003\35&\314P6\231;N\2502\342\343\27\253\334V\6\1775\332\373\317\21e(\4\365\375\363.\366eW\36\313\213\2N\364\240\252\31\261\231\274\230Y\354\255\253w\240\302\2240\241\362V\tZG\331$\231\327M\253O\364\377\255\4\3256\2\301G\317\235\257v8\244\356k\3726\343\t\317\226R\351\202\303c\322Y\31}\27\tX\347\202k\253\321>\31\272\271`\203(k\3\'|\261\35-\204\260\f-\214\220u\236@\273\2473\324\376\235\346\320\32xv\374#\23q\246\312\331AR,\233\351U\33\375\346S\222\36\226\346\1\330\363\r_3\236\311;\313\373u\20\312\34\264\335\253\232_\375\25\207\34$\177i\373\301\311\r\273\356\245&\22\340\311 6\245\310ol\340\4\'\221A\216\34?\254<\241b\37\265\354\354Z\275e\251\357\363\325hd\236\r\260_b\202\37\251\224\274\375\267\22\272\260\306^v\370\f\224ji\244\t<\231\255\266\275\36\373\352\251\364\336PK\263\324\366\307dv\36\0014\353_Q\202\33fMem0\2\261 vA\37Y\304C\351\231\3266\347\347\3050\2735\306\247F\313\262\276\7\304h\352^\333\256}\242Ax-\350\3\375\263\201\327f \213\276\1\3610\\\344\210Y7C\220{\270\324R\200\306-\306\246X\337\264\240\371\363\307,(O\226\26^g\274q\341\242Z\20\37\7\17\232\221_$\250i\336+O\231\37\233\233o4\352\360\r\213\316gS\206\20\221O\364M\254x\242\257\207\1M\0042\353Q\6\265\313*\213\207\332=Y~\226\375\313~\312yx\261\37\354\v\271\2nGL\355 \7\271\212\34\"T\251\25\246\3174@%\244\30\24E\210\205\312\223C\"\220\243,\301tCj\f\16\2449\2\362\232:t\225\305q\300q.g\351\v\307\345N\210N\260\21z\275\305_\17\236\202A\3251-[0\'\217\342\235\222\260\34?\232n\327{&N{\206\214\16\224\343\355\270\n)\374X\227l\343\375\342*\305/\222\34\207X\342K\26\251\304\235&NzF\272\274\347\0202\355\343\25\3237\372\250\355\7OT\313\20j\240\3wu\263\261\246\375n\225g\262\210!\330\376\260+\374\216\313Q\344u\243\362\325\324\242\0045\266\2339\227Z\232<\327R\324\213b\270\t\0319\224\3724\261\227\233\360\313\234\313\35MU\310@\240\22\03233\352\326\266\307au_E-\275\223\371w\221\317\0200\343\353\23089x\25\247\266\203l\334p\321R\330\221\213\364\274}\206\366\10jB\241\274\305\312\244\4\374\t\"\tAmq\3652\317k\6\7\245\241\310\201\224v\r\177\247\0\352\310\25v\23\217/r\345(\305\200I@\223\227]\246|\214\f\356!\3\0\0\0\0\0\325\24\0\0\0\0\2\0\7connect\0?\360\0\0\0\0\0\0\3\0\3app\2\0\4test\0\vaudioCodecs\0@\2038\0\0\0\0\0\0\10flashVer\2\0\rWIN 9,0,999,0\0\4fpad\1\1\0\7pageUrl\6\0\6swfUrl\2\0\30file://hello-world-\3036.swf\0\5tcUrl\2\0\25rtmp://localhost/test\0\vvideoCodecs\0@_\0\0\0\0\0\0\0\rvideoFunction\0?\360\0\0\0\0\0\0\0\0\t
-recv \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240\2\0\0\0\0\0\5\6\0\0\0\0\0&%\240\2\2\0\0\0\0\0\6\4\0\0\0\0\0\0\0\0\0\0\3\0\0\0\0\0\277\24\0\0\0\0\2\0\7_result\0?\360\0\0\0\0\0\0\3\0\6fmsVer\2\0\16FMS/3,0,0,1157\0\fcapabilities\0@?\0\0\0\0\0\0\0\0\t\3\0\5level\2\0\6status\0\4code\2\0\35NetConnection.Connect.Success\0\v\303description\2\0\25Connection succeeded.\0\16objectEncoding\0\0\0\0\0\0\0\0\0\0\0\t
-send \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240\3\0\0\6\0\0\21\24\0\0\0\0\2\0\4ping\0\0\0\0\0\0\0\0\0\5
+recv \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240
+recv \2\0\0\0\0\0\5\6\0\0\0\0\0&%\240\2
+recv \2\0\0\0\0\0\6\4\0\0\0\0\0\0\0\0\0\0
+recv \3\0\0\0\0\0\277\24\0\0\0\0\2\0\7_result\0?\360\0\0\0\0\0\0\3\0\6fmsVer\2\0\16FMS/3,0,0,1157\0\fcapabilities\0@?\0\0\0\0\0\0\0\0\t\3\0\5level\2\0\6status\0\4code\2\0\35NetConnection.Connect.Success\0\v
+recv \303description\2\0\25Connection succeeded.\0\16objectEncoding\0\0\0\0\0\0\0\0\0\0\0\t
+send \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240
+send \3\0\0\6\0\0\21\24\0\0\0\0\2\0\4ping\0\0\0\0\0\0\0\0\0\5
recv \3\0\0\0\0\0\21\24\0\0\0\0\2\0\4pong\0\0\0\0\0\0\0\0\0\5
diff --git a/test/rtmp/hello-world-7.swf.dump b/test/rtmp/hello-world-7.swf.dump
index 763cdf5..d788ace 100644
--- a/test/rtmp/hello-world-7.swf.dump
+++ b/test/rtmp/hello-world-7.swf.dump
@@ -1,6 +1,11 @@
send \3\0\0\0\0\0\0\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4
recv \3\2-\340\n\0\0\0\0%\324\17\27\325)99\30\342\340\252\224\5\355\240\240+,\213\244\210\266\261\260T\377\342\3407\367\335$x\276\365%\265\246 JM\275\361\330\3458,\232\303\312m\336\4O\212\350nH\351#\331\323\225\217\335\260\34<\0\33\17\357\221\205\331*\\Oc\275s\204\377\211+\340\363\332\217\327D\232\304(\306\3348\225\314\337~\206M\314\241\23]\223I\363\326\253\235\277\245n\336\301\262\232M+sE=]\371V#\345\337\277R\373>\17\32\26\300Z\370\306R<})\355OZ\365;\274\351\235\252\30\314\356\25\216^#\274?\35W\37\206\361\346)\r\201{\21\32\20\327\366\20i;\215\336\261\3578\2\331\233\204\27X\313#W|YB\346\375\256\354\36\340 o\236B\226\373\327\2470\365\204n?n\215\250\340\252\351\373q_\204Nsw\223-;\202\333\245\37\260;j\354\200\254u~\3Q=\302\350\344?\372\335\202\324\236\f:\353q\301l\332Kn? \333\234\5\344\362\352\317k\3750n\233\35\374nb\242p\300\v\235\24Y\243\34\243\255e\35\245\257\232\243\323e\216\323f\210A\315%\233\27Wo\\\337\273.\311\232\331\340\"P\"\225=\nP\3760\2365\231\20\353Vig\303\346\365f \235;E\230\27r\307K\260\256\10\262\221\"\365\25\220\310\265\307\323Cs&\37DY\266\235\315\221l\356h\355f:\361F\353/z]\264\36\244\367\227\200g\2761\324\373\335\2775\265\324\273\251\375\4\247xW\370\222\354\371M\333\276<\247\260\26\221\300\361C-\202\0\231\243V\337%\t\267y\326\247\351 at h,8\331\362\203\225`d\34\355\332\326\22#@C\0226G^k\315\215Sn\231\220(\345v\207\277\5\334\346;\10\2358iR0dE\300y\222\350A\354?cX\10^\245-\265\5^OHj8\204uPj7\0331\374\323\342\205\216\263\375\6\202w)\366\321\16\t\36\262\222\205e\v\373T\236\377\236\7\362\276\355\220\3\17\302/_\211\215C\222\214\225\270\212)\271D\2339\347n2\274\252\252\215\21v\31Pq\367\3633W\267\37\315TW\344A\322y\256\345-\230\221\204i\222\377\30\10.Z\v\212\316\364`\4\272\354M\373\214\324\300\253\26\334\3668\205\233\352+\352\351.\342\234\327\2=\312\201\3578\201\200,O`\344\252\r\223\320\277N\3720\246m\307\211k\217\374\0\211\310i^\316\267\3031\254\241\361\365\25\3277;\254\222D\372W\331;\313B\2743\337\374L\272\366_*k\202\272\2243\25#X?\362\24\204I\31V\315\224\376T@\240\361io\244P&1\241\252\275k\356I\226\374\224\366UF\200\313\221\343M\233\30\v\225\226\0327\236\212\31\273\267eM\205o\223,1\t\300\201Z?\355\235\376F+\235\276ed\304eT\246\205R\235z\213\253O\237v2\206\272\0\205jji\265\356\350\276\204\231^\325\347x\7\215\334C| \3\2569/\\\177b{\v<\216\23\216\347/\317\341\302\327\327\345\264/\3249}K\307*\354\302\336\232\311\224\266\263\245W\375#\266\5[\225\310\274\341\256\232\301\234$t+0tK\4D\337\315\331$7_\204/P\330\216B\344l@\230\242\216\200\315\241\201T\33U\337\34\314\306\321\201Q\n2O\32$\310\245\16\210\227\377!t\224\263+\"1\230t -P\253\21&zz\tt!\305\244\35\243\335AG\344E&~\362\275?\272`vb?\37C\215=(\2134Y1\264\234\210\213\225\222\2619N\276X8\35hC\305&\344\225\343\3%\270\374\2104\37317 z\216D\270\r\374\235\353\6\246\227\f:c\337\26d\201]\346\204\353\16p\334\230U+\240\267\243p\17D\223B\336:h\2\350K\25\353xD\235|\311\221\t\251<g!D\375|\2503\24\331D\301\fbO\0\336\257[\236\213\262|\1\3^\371%I\344\n}\364\265\32 \36\6\374&\375\32#y\247I\351\221Z\277\310u4\206\10I\335T=\213L\243\252*\312O.8\212h\314\2344Z\2349\221\342\307\230P!\222\310\264K\366t\\\257\251\16\213\377\3\201\177e\332W\221\275)\244\273\377\4\240n/)\334O\241\236\261\270\216+\177\6\23\260E7;p\205\315\243\304s}:\37wHMVA\32\254X\177\236\363\240\363\371o\347\33T\21\347jr\317C\262\267\271\t\226#\320\245\212\351\343\\W\364\371\353\202\7[\24\366\245U\2713\370\307\341-\245\271\20\7\305X8\243]\261\200\352X&\202\210\337*\307\327\34{\20\301\252r1\366\243\2\2418,1\25\263\375=5\34\213\336\247\200\346`\306\257{\263\335\311]\337\24\17\314\354\232\220\2521lN\312\335S+\320o\341\364B\202d\243\375\240.\302He7\321\373\'r\315X\1\270Y\224A\241\3\33\0352t\306\272\244\274b\372\307\221\321\376wZ\10\\h\354\213\310?\310X\235\266\"}\323$o\33M\210\325\24\304\354\301\243\30\341\3566,Y\203\332\257\0071c\34\334\334\241\217c4\343\v\336\1\242\353/p\251\333E\242\17\264\2126kf\364\16\327WH\317\304\314V\344\245\363\231\2311\207\365\251\17Z\335\207\251]]\365\322o\320\204w\313\350Fk\364\271,>\315U\\\356)b\10\317\202\23}x\31\210\270\234/\206\0002\224\203\343\314\f\32=\371\370\260\221,\377\n\261\303y\336\236\340\316\347VZ\6\322\0\366\252\277\210M\362\347\366E\372\251\216\321\352_,*N\7y]\300\3537\\\32<\37V`2)_H\2708\275_9bn\0\0\0\0\0\0\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4
send \2-\340\n\0\0\0\0%\324\17\27\325)99\30\342\340\252\224\5\355\240\240+,\213\244\210\266\261\260T\377\342\3407\367\335$x\276\365%\265\246 JM\275\361\330\3458,\232\303\312m\336\4O\212\350nH\351#\331\323\225\217\335\260\34<\0\33\17\357\221\205\331*\\Oc\275s\204\377\211+\340\363\332\217\327D\232\304(\306\3348\225\314\337~\206M\314\241\23]\223I\363\326\253\235\277\245n\336\301\262\232M+sE=]\371V#\345\337\277R\373>\17\32\26\300Z\370\306R<})\355OZ\365;\274\351\235\252\30\314\356\25\216^#\274?\35W\37\206\361\346)\r\201{\21\32\20\327\366\20i;\215\336\261\3578\2\331\233\204\27X\313#W|YB\346\375\256\354\36\340 o\236B\226\373\327\2470\365\204n?n\215\250\340\252\351\373q_\204Nsw\223-;\202\333\245\37\260;j\354\200\254u~\3Q=\302\350\344?\372\335\202\324\236\f:\353q\301l\332Kn? \333\234\5\344\362\352\317k\3750n\233\35\374nb\242p\300\v\235\24Y\243\34\243\255e\35\245\257\232\243\323e\216\323f\210A\315%\233\27Wo\\\337\273.\311\232\331\340\"P\"\225=\nP\3760\2365\231\20\353Vig\303\346\365f \235;E\230\27r\307K\260\256\10\262\221\"\365\25\220\310\265\307\323Cs&\37DY\266\235\315\221l\356h\355f:\361F\353/z]\264\36\244\367\227\200g\2761\324\373\335\2775\265\324\273\251\375\4\247xW\370\222\354\371M\333\276<\247\260\26\221\300\361C-\202\0\231\243V\337%\t\267y\326\247\351 at h,8\331\362\203\225`d\34\355\332\326\22#@C\0226G^k\315\215Sn\231\220(\345v\207\277\5\334\346;\10\2358iR0dE\300y\222\350A\354?cX\10^\245-\265\5^OHj8\204uPj7\0331\374\323\342\205\216\263\375\6\202w)\366\321\16\t\36\262\222\205e\v\373T\236\377\236\7\362\276\355\220\3\17\302/_\211\215C\222\214\225\270\212)\271D\2339\347n2\274\252\252\215\21v\31Pq\367\3633W\267\37\315TW\344A\322y\256\345-\230\221\204i\222\377\30\10.Z\v\212\316\364`\4\272\354M\373\214\324\300\253\26\334\3668\205\233\352+\352\351.\342\234\327\2=\312\201\3578\201\200,O`\344\252\r\223\320\277N\3720\246m\307\211k\217\374\0\211\310i^\316\267\3031\254\241\361\365\25\3277;\254\222D\372W\331;\313B\2743\337\374L\272\366_*k\202\272\2243\25#X?\362\24\204I\31V\315\224\376T@\240\361io\244P&1\241\252\275k\356I\226\374\224\366UF\200\313\221\343M\233\30\v\225\226\0327\236\212\31\273\267eM\205o\223,1\t\300\201Z?\355\235\376F+\235\276ed\304eT\246\205R\235z\213\253O\237v2\206\272\0\205jji\265\356\350\276\204\231^\325\347x\7\215\334C| \3\2569/\\\177b{\v<\216\23\216\347/\317\341\302\327\327\345\264/\3249}K\307*\354\302\336\232\311\224\266\263\245W\375#\266\5[\225\310\274\341\256\232\301\234$t+0tK\4D\337\315\331$7_\204/P\330\216B\344l@\230\242\216\200\315\241\201T\33U\337\34\314\306\321\201Q\n2O\32$\310\245\16\210\227\377!t\224\263+\"1\230t -P\253\21&zz\tt!\305\244\35\243\335AG\344E&~\362\275?\272`vb?\37C\215=(\2134Y1\264\234\210\213\225\222\2619N\276X8\35hC\305&\344\225\343\3%\270\374\2104\37317 z\216D\270\r\374\235\353\6\246\227\f:c\337\26d\201]\346\204\353\16p\334\230U+\240\267\243p\17D\223B\336:h\2\350K\25\353xD\235|\311\221\t\251<g!D\375|\2503\24\331D\301\fbO\0\336\257[\236\213\262|\1\3^\371%I\344\n}\364\265\32 \36\6\374&\375\32#y\247I\351\221Z\277\310u4\206\10I\335T=\213L\243\252*\312O.8\212h\314\2344Z\2349\221\342\307\230P!\222\310\264K\366t\\\257\251\16\213\377\3\201\177e\332W\221\275)\244\273\377\4\240n/)\334O\241\236\261\270\216+\177\6\23\260E7;p\205\315\243\304s}:\37wHMVA\32\254X\177\236\363\240\363\371o\347\33T\21\347jr\317C\262\267\271\t\226#\320\245\212\351\343\\W\364\371\353\202\7[\24\366\245U\2713\370\307\341-\245\271\20\7\305X8\243]\261\200\352X&\202\210\337*\307\327\34{\20\301\252r1\366\243\2\2418,1\25\263\375=5\34\213\336\247\200\346`\306\257{\263\335\311]\337\24\17\314\354\232\220\2521lN\312\335S+\320o\341\364B\202d\243\375\240.\302He7\321\373\'r\315X\1\270Y\224A\241\3\33\0352t\306\272\244\274b\372\307\221\321\376wZ\10\\h\354\213\310?\310X\235\266\"}\323$o\33M\210\325\24\304\354\301\243\30\341\3566,Y\203\332\257\0071c\34\334\334\241\217c4\343\v\336\1\242\353/p\251\333E\242\17\264\2126kf\364\16\327WH\317\304\314V\344\245\363\231\2311\207\365\251\17Z\335\207\251]]\365\322o\320\204w\313\350Fk\364\271,>\315U\\\356)b\10\317\202\23}x\31\210\270\234/\206\0002\224\203\343\314\f\32=\371\370\260\221,\377\n\261\303y\336\236\340\316\347VZ\6\322\0\366\252\277\210M\362\347\366E\372\251\216\321\352_,*N\7y]\300\3537\\\32<\37V`2)_H\2708\275_9bn\3\0\0\0\0\0\325\24\0\0\0\0\2\0\7connect\0?\360\0\0\0\0\0\0\3\0\3app\2\0\4test\0\vaudioCodecs\0@\2038\0\0\0\0\0\0\10flashVer\2\0\rWIN 9,0,999,0\0\4fpad\1\1\0\7pageUrl\6\0\6swfUrl\2\0\30file://hello-world-\3037.swf\0\5tcUrl\2\0\25rtmp://localhost/test\0\vvideoCodecs\0@_\0\0\0\0\0\0\0\rvideoFunction\0?\360\0\0\0\0\0\0\0\0\t
-recv \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240\2\0\0\0\0\0\5\6\0\0\0\0\0&%\240\2\2\0\0\0\0\0\6\4\0\0\0\0\0\0\0\0\0\0\3\0\0\0\0\0\277\24\0\0\0\0\2\0\7_result\0?\360\0\0\0\0\0\0\3\0\6fmsVer\2\0\16FMS/3,0,0,1157\0\fcapabilities\0@?\0\0\0\0\0\0\0\0\t\3\0\5level\2\0\6status\0\4code\2\0\35NetConnection.Connect.Success\0\v\303description\2\0\25Connection succeeded.\0\16objectEncoding\0\0\0\0\0\0\0\0\0\0\0\t
-send \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240\3\0\0\6\0\0\21\24\0\0\0\0\2\0\4ping\0\0\0\0\0\0\0\0\0\5
+recv \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240
+recv \2\0\0\0\0\0\5\6\0\0\0\0\0&%\240\2
+recv \2\0\0\0\0\0\6\4\0\0\0\0\0\0\0\0\0\0
+recv \3\0\0\0\0\0\277\24\0\0\0\0\2\0\7_result\0?\360\0\0\0\0\0\0\3\0\6fmsVer\2\0\16FMS/3,0,0,1157\0\fcapabilities\0@?\0\0\0\0\0\0\0\0\t\3\0\5level\2\0\6status\0\4code\2\0\35NetConnection.Connect.Success\0\v
+recv \303description\2\0\25Connection succeeded.\0\16objectEncoding\0\0\0\0\0\0\0\0\0\0\0\t
+send \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240
+send \3\0\0\6\0\0\21\24\0\0\0\0\2\0\4ping\0\0\0\0\0\0\0\0\0\5
recv \3\0\0\0\0\0\21\24\0\0\0\0\2\0\4pong\0\0\0\0\0\0\0\0\0\5
diff --git a/test/rtmp/hello-world-8.swf.dump b/test/rtmp/hello-world-8.swf.dump
index 7fb8a01..265e646 100644
--- a/test/rtmp/hello-world-8.swf.dump
+++ b/test/rtmp/hello-world-8.swf.dump
@@ -1,6 +1,11 @@
send \3\0\0\0\0\0\0\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4
recv \3\2-\342\374\0\0\0\0+)\24\264<v\177\257Pd\322\277\367\336\301\323L\3233\0\253\335bc\177\234\366}\230\216\213\346\236=\271I\25dl\20 \371\v\241~\355w&\1\367xx\35\203\310\217C\310\226\366)\233\247\377k:\264\270\202\214\257Z,\236\277\33\207`\323\226i\266\212\323\304/\215\3\334\340(\235b\253\5\335\241\202)\23\375\265\6\243\215\t\266p\17\276\204\233\226\v\333%f\205%z\v\340\350\'=X\277\223\307\272\336-L\277\306\226`\255\277k\345\271\305B\363\270\241-6\272[,\360\241_\"\7\353\221-)\233=/\"\307\212!c\236\'Dnm\371\7<\363b\"lV\0038\257\271\222\'P\373i\357>*${m^PQO\311\303\316\331\0dI\365O\3504@\210\241\"&\352U+1\244\243vDx\227J\347\302\0039>\206B0\201\313\220&\323\221\345\265\315\356\35#(\215\26X\'d0*\230r s\302\344\252\345\230\313K74w\257/>\307\1\226\260]4\374r&\301.!b/\213\332\320\234\232\363c\vG\376\365\36|4@\2200l\235;Mk\320D\245n\300L\257\370\367\374d\10:\276\t\346\f\304\310X\25\342\350\216t\0\355l.`\274\331P\226&,\17\323\327\3717*\372\242\202\221Dx\322\211\204\327N\226\20V\21\263*Hl\314\311\370\252UR\345\220\350c\263y\265$\6\246\3\3742\256\333\231/\243g\35\257A\254t\340\256\322YP\0336\302\240\n\327\1\352\326F\274\2232\324x\256\304\264z\351\25\260\373Am[8\306Q\312:\257\340v\302\227\0\22#8j\354\374\363\247VT\352\277\\\206\17TE\316\35]\225d2\360\310/\227h\370#\330\241\21p\3460\250\207>\10?\3500\327o\352\251x.\350\217-\334\336zx\236\357\277J\274\241\211\37\372\v\316O\16\16\344W\347\227i\345\265\344\231\241\7g\213\t\376\236%>oKf\33\'\340 at n\375\327\34m\5\356\226\363\376\350\234\271\361\21\306U\331AT$\272\34xf\336\217\256\240\301\370\310\344\222\265ZZ,\\]f\347\337\21\332\372*\331\31MR\372&&T\"\"\360\20\313S*\204\354\233\322\220kZ\331\265\254U\204\200=,\306\201\226\rI\\\6w\244\3061\2771H~\317\31t*N\324\214\211\243\272\206Ld\300\2\27\303\352\232}n\211\274us\264\342\267\343\177\0048\5\376CI)\311H\23Pj\356\361{b\n\256\360\2\277\267\274\242\371A\302\261\227\273\31\250\327\204<\360Kc\21\230\220L\335u d!\33\321\276\202\346mSzt\255Z\300\346\207k\345\274N3R\253\30\361\256\361\5\30399\270-\24\234n\1\352uj\351\371\"$F\303\374\211\324\241\30R\372\337\ruS\31$\346\243\367[\277\30\306\304\354P\n\230j\362OJ\'pV\3\302\275\345K\343\236\t\25\346\372\302R43!z\274\241\33\0319wW\242G#v2%\314\344\262\366\230\255z\333\36#\235zlUM\355\203\316o\0268\224Jq\207 at P\373]\261K\236\253\243\265A\315BB\206\351\340\222g}[\234\330\274W&\365\310\37B\227J\353\216\37`\37\344}\0374(\375\31\2344vv\325\246\255c\364\vP\246\375\337D\337\372\221\225\323\37\300|\36\250\211\7K&\310B\263\366\356\230:\360\327\25\273\224\302\200\361\347\303LDc\1\304\275\25\36\17\311\240\374\340!\315\347\377\5\205\327\\\371\35zJ&\257\213rM\225\266\f\237\235\220\375\352\203[?e\377C\v6\370o\232\31\277 E\3336\216\230\r\322\255\30\205Q\375b\367\272\20\7\322\224\302\262,\332(9+\316~c3|\260\202\3114e\223\257tXz\316=\307\235\342\241\370\6\336\204\265:-\232\276\274[*\357\265\320\23H\t\364`\342\205\362\32\16\227\212p\237\211\313b\367\356\330\4O\317\240;d\346\'\234ol\347|\306\3\272\311\350\365D\210;\262}>3\230\361\2113\2776Vg\205\273\223\222\372\2\253Z\'\2701\355\220$\300_\4\21\223m)>\235\3771\316ge@\277\245\304\266\3\"t3\317\337\311\361(2#\211\336)\v\251\313\240o\222\17\230\347\276\371\377\235\316\33\262\260\336G\2119\203\30\325B\364\24\2424\220:\210w\347g\272\241VM\362{Ve6\10~ d\32\221\v\321]\'oI\201B\37a\16j\301\10\361\274\343\22\316\36\275\226b0\3058\341\335\277h\365(a\321\320 p\217\347\263*\302r\347\361\310\245\"\225\354\275\375\26\244d,\2\5\217\2\210\\\356\33\301\26\273P\242\24T\214\177\n\342-\361\346\v\243\246e\203O\334\222\206\302\r\332l\256\373\250\'\216\323\236\330\t\341\\\205\354g\304\273\372y\246\330\362cBg\363T(\217\324\tS\375\375\262%\201\215M\3AjT\321y|\213\353\254\330\206\355K\234kCT\375\21469\327e\362\r\373p>s\242?\215\10\213c\35\301b\221\247\227\26\7\23\226\33\203\341>\1\213&\0Y\236\307\r\303\210\342\246\207\20{rl\362\340\31\331\257uY\301\347[{\200%\264\266\35tl\21\0216$<\277;\362\260\207Z\226W)$81\236\24g\5\264\214(\317o\30\214c\377U@\223\242N\330\262\225\234K\254\253R\275\20\33\306\0217\16\300rXX\335\254\n\242\25\304\375\325\245\231yiO[6\263R\27]\r%9\360M\267\0070\375\324\10n\363:R\354\372\30\f^\3773\351\0211\226\32\227F\317c_\326\272\33i%\262\275M\2047\223\1\332D\356m\272\0\0\0\0\0\0\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4\0\325\0Z\0#\0\0\0\1\0v\0\357\0<\0m\0\322\0\373\0\270\0\31\0n\0G\0t\0\5\0J\0\323\0p\0001\0f\0\237\0\254\0\235\0\302\0\253\0(\0I\0^\0\367\0\344\0005\0:\0\203\0\340\0a\0V\0O\0\34\0\315\0\262\0[\0\230\0y\0N\0\247\0T\0e\0*\0003\0P\0\221\0F\0\377\0\214\0\375\0\242\0\v\0\10\0\251\0>\0W\0\304\0\225\0\32\0\343\0\300\0\301\0006\0\257\0\374\0-\0\222\0\273\0x\0\331\0.\0\7\0004\0\305\0\n\0\223\0000\0\361\0&\0_\0l\0]\0\202\0k\0\350\0\t\0\36\0\267\0\244\0\365\0\372\0C\0\240\0!\0\26\0\17\0\334\0\215\0r\0\33\0X\0009\0\16\0g\0\24\0%\0\352\0\363\0\20\0Q\0\6\0\277\0L\0\275\0b\0\313\0\310\0i\0\376\0\27\0\204\0U\0\332\0\243\0\200\0\201\0\366\0o\0\274\0\355\0R\0{\0008\0\231\0\356\0\307\0\364\0\205\0\312\0S\0\360\0\261\0\346\0\37\0,\0\35\0B\0+\0\250\0\311\0\336\0w\0d\0\265\0\272\0\3\0`\0\341\0\326\0\317\0\234\0M\0002\0\333\0\30\0\371\0\316\0\'\0\324\0\345\0\252\0\263\0\320\0\21\0\306\0\177\0\f\0}\0\"\0\213\0\210\0)\0\276\0\327\0D\0\25\0\232\0c\0@\0A\0\266\0/\0|\0\255\0\22\0;\0\370\0Y\0\256\0\207\0\264\0E\0\212\0\23\0\260\0q\0\246\0\337\0\354\0\335\0\2\0\353\0h\0\211\0\236\0007\0$\0u\0z\0\303\0 \0\241\0\226\0\217\0\\\0\r\0\362\0\233\0\330\0\271\0\216\0\347\0\224\0\245\0j\0s\0\220\0\321\0\206\0?\0\314\0=\0\342\0K\0H\0\351\0~\0\227\0\4
send \2-\342\374\0\0\0\0+)\24\264<v\177\257Pd\322\277\367\336\301\323L\3233\0\253\335bc\177\234\366}\230\216\213\346\236=\271I\25dl\20 \371\v\241~\355w&\1\367xx\35\203\310\217C\310\226\366)\233\247\377k:\264\270\202\214\257Z,\236\277\33\207`\323\226i\266\212\323\304/\215\3\334\340(\235b\253\5\335\241\202)\23\375\265\6\243\215\t\266p\17\276\204\233\226\v\333%f\205%z\v\340\350\'=X\277\223\307\272\336-L\277\306\226`\255\277k\345\271\305B\363\270\241-6\272[,\360\241_\"\7\353\221-)\233=/\"\307\212!c\236\'Dnm\371\7<\363b\"lV\0038\257\271\222\'P\373i\357>*${m^PQO\311\303\316\331\0dI\365O\3504@\210\241\"&\352U+1\244\243vDx\227J\347\302\0039>\206B0\201\313\220&\323\221\345\265\315\356\35#(\215\26X\'d0*\230r s\302\344\252\345\230\313K74w\257/>\307\1\226\260]4\374r&\301.!b/\213\332\320\234\232\363c\vG\376\365\36|4@\2200l\235;Mk\320D\245n\300L\257\370\367\374d\10:\276\t\346\f\304\310X\25\342\350\216t\0\355l.`\274\331P\226&,\17\323\327\3717*\372\242\202\221Dx\322\211\204\327N\226\20V\21\263*Hl\314\311\370\252UR\345\220\350c\263y\265$\6\246\3\3742\256\333\231/\243g\35\257A\254t\340\256\322YP\0336\302\240\n\327\1\352\326F\274\2232\324x\256\304\264z\351\25\260\373Am[8\306Q\312:\257\340v\302\227\0\22#8j\354\374\363\247VT\352\277\\\206\17TE\316\35]\225d2\360\310/\227h\370#\330\241\21p\3460\250\207>\10?\3500\327o\352\251x.\350\217-\334\336zx\236\357\277J\274\241\211\37\372\v\316O\16\16\344W\347\227i\345\265\344\231\241\7g\213\t\376\236%>oKf\33\'\340 at n\375\327\34m\5\356\226\363\376\350\234\271\361\21\306U\331AT$\272\34xf\336\217\256\240\301\370\310\344\222\265ZZ,\\]f\347\337\21\332\372*\331\31MR\372&&T\"\"\360\20\313S*\204\354\233\322\220kZ\331\265\254U\204\200=,\306\201\226\rI\\\6w\244\3061\2771H~\317\31t*N\324\214\211\243\272\206Ld\300\2\27\303\352\232}n\211\274us\264\342\267\343\177\0048\5\376CI)\311H\23Pj\356\361{b\n\256\360\2\277\267\274\242\371A\302\261\227\273\31\250\327\204<\360Kc\21\230\220L\335u d!\33\321\276\202\346mSzt\255Z\300\346\207k\345\274N3R\253\30\361\256\361\5\30399\270-\24\234n\1\352uj\351\371\"$F\303\374\211\324\241\30R\372\337\ruS\31$\346\243\367[\277\30\306\304\354P\n\230j\362OJ\'pV\3\302\275\345K\343\236\t\25\346\372\302R43!z\274\241\33\0319wW\242G#v2%\314\344\262\366\230\255z\333\36#\235zlUM\355\203\316o\0268\224Jq\207 at P\373]\261K\236\253\243\265A\315BB\206\351\340\222g}[\234\330\274W&\365\310\37B\227J\353\216\37`\37\344}\0374(\375\31\2344vv\325\246\255c\364\vP\246\375\337D\337\372\221\225\323\37\300|\36\250\211\7K&\310B\263\366\356\230:\360\327\25\273\224\302\200\361\347\303LDc\1\304\275\25\36\17\311\240\374\340!\315\347\377\5\205\327\\\371\35zJ&\257\213rM\225\266\f\237\235\220\375\352\203[?e\377C\v6\370o\232\31\277 E\3336\216\230\r\322\255\30\205Q\375b\367\272\20\7\322\224\302\262,\332(9+\316~c3|\260\202\3114e\223\257tXz\316=\307\235\342\241\370\6\336\204\265:-\232\276\274[*\357\265\320\23H\t\364`\342\205\362\32\16\227\212p\237\211\313b\367\356\330\4O\317\240;d\346\'\234ol\347|\306\3\272\311\350\365D\210;\262}>3\230\361\2113\2776Vg\205\273\223\222\372\2\253Z\'\2701\355\220$\300_\4\21\223m)>\235\3771\316ge@\277\245\304\266\3\"t3\317\337\311\361(2#\211\336)\v\251\313\240o\222\17\230\347\276\371\377\235\316\33\262\260\336G\2119\203\30\325B\364\24\2424\220:\210w\347g\272\241VM\362{Ve6\10~ d\32\221\v\321]\'oI\201B\37a\16j\301\10\361\274\343\22\316\36\275\226b0\3058\341\335\277h\365(a\321\320 p\217\347\263*\302r\347\361\310\245\"\225\354\275\375\26\244d,\2\5\217\2\210\\\356\33\301\26\273P\242\24T\214\177\n\342-\361\346\v\243\246e\203O\334\222\206\302\r\332l\256\373\250\'\216\323\236\330\t\341\\\205\354g\304\273\372y\246\330\362cBg\363T(\217\324\tS\375\375\262%\201\215M\3AjT\321y|\213\353\254\330\206\355K\234kCT\375\21469\327e\362\r\373p>s\242?\215\10\213c\35\301b\221\247\227\26\7\23\226\33\203\341>\1\213&\0Y\236\307\r\303\210\342\246\207\20{rl\362\340\31\331\257uY\301\347[{\200%\264\266\35tl\21\0216$<\277;\362\260\207Z\226W)$81\236\24g\5\264\214(\317o\30\214c\377U@\223\242N\330\262\225\234K\254\253R\275\20\33\306\0217\16\300rXX\335\254\n\242\25\304\375\325\245\231yiO[6\263R\27]\r%9\360M\267\0070\375\324\10n\363:R\354\372\30\f^\3773\351\0211\226\32\227F\317c_\326\272\33i%\262\275M\2047\223\1\332D\356m\272\3\0\0\0\0\0\325\24\0\0\0\0\2\0\7connect\0?\360\0\0\0\0\0\0\3\0\3app\2\0\4test\0\vaudioCodecs\0@\2038\0\0\0\0\0\0\10flashVer\2\0\rWIN 9,0,999,0\0\4fpad\1\1\0\7pageUrl\6\0\6swfUrl\2\0\30file://hello-world-\3038.swf\0\5tcUrl\2\0\25rtmp://localhost/test\0\vvideoCodecs\0@_\0\0\0\0\0\0\0\rvideoFunction\0?\360\0\0\0\0\0\0\0\0\t
-recv \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240\2\0\0\0\0\0\5\6\0\0\0\0\0&%\240\2\2\0\0\0\0\0\6\4\0\0\0\0\0\0\0\0\0\0\3\0\0\0\0\0\277\24\0\0\0\0\2\0\7_result\0?\360\0\0\0\0\0\0\3\0\6fmsVer\2\0\16FMS/3,0,0,1157\0\fcapabilities\0@?\0\0\0\0\0\0\0\0\t\3\0\5level\2\0\6status\0\4code\2\0\35NetConnection.Connect.Success\0\v\303description\2\0\25Connection succeeded.\0\16objectEncoding\0\0\0\0\0\0\0\0\0\0\0\t
-send \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240\3\0\0\6\0\0\21\24\0\0\0\0\2\0\4ping\0\0\0\0\0\0\0\0\0\5
+recv \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240
+recv \2\0\0\0\0\0\5\6\0\0\0\0\0&%\240\2
+recv \2\0\0\0\0\0\6\4\0\0\0\0\0\0\0\0\0\0
+recv \3\0\0\0\0\0\277\24\0\0\0\0\2\0\7_result\0?\360\0\0\0\0\0\0\3\0\6fmsVer\2\0\16FMS/3,0,0,1157\0\fcapabilities\0@?\0\0\0\0\0\0\0\0\t\3\0\5level\2\0\6status\0\4code\2\0\35NetConnection.Connect.Success\0\v
+recv \303description\2\0\25Connection succeeded.\0\16objectEncoding\0\0\0\0\0\0\0\0\0\0\0\t
+send \2\0\0\0\0\0\4\5\0\0\0\0\0&%\240
+send \3\0\0\6\0\0\21\24\0\0\0\0\2\0\4ping\0\0\0\0\0\0\0\0\0\5
recv \3\0\0\0\0\0\21\24\0\0\0\0\2\0\4pong\0\0\0\0\0\0\0\0\0\5
commit 6636c183c3d8b9cd30fed39aeffdb5da90045627
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 20:41:03 2008 +0100
add a tool for rewriting strace outputs to test output
diff --git a/tools/Makefile.am b/tools/Makefile.am
index bfaecf2..0b155e2 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,6 +1,6 @@
-noinst_PROGRAMS = swfdec-extract dump crashfinder
+noinst_PROGRAMS = swfdec-extract dump crashfinder rtmp-trace
-crashfinder_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
+crashfinder_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(CAIRO_CFLAGS)
crashfinder_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS)
crashfinder_SOURCES = crashfinder.c
@@ -9,3 +9,6 @@ dump_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
swfdec_extract_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(CAIRO_CFLAGS)
swfdec_extract_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS)
+
+rtmp_trace_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
+rtmp_trace_LDFLAGS = $(SWFDEC_LIBS)
diff --git a/tools/rtmp-trace.c b/tools/rtmp-trace.c
new file mode 100644
index 0000000..26e5b18
--- /dev/null
+++ b/tools/rtmp-trace.c
@@ -0,0 +1,399 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <swfdec/swfdec.h>
+#include <swfdec/swfdec_rtmp_header.h>
+#include <swfdec/swfdec_rtmp_packet.h>
+
+static char *
+swfdec_buffer_to_string (SwfdecBuffer *b)
+{
+ GString *string;
+ guint i;
+
+ g_return_val_if_fail (b != NULL, NULL);
+
+ string = g_string_new ("");
+ for (i = 0; i < b->length; i++) {
+ guchar c = (guchar) b->data[i];
+ switch (c) {
+ case '\"':
+ case '\'':
+ case '\\':
+ g_string_append_c (string, '\\');
+ g_string_append_c (string, (char) c);
+ break;
+ case '\f':
+ g_string_append_c (string, '\\');
+ g_string_append_c (string, 'f');
+ break;
+ case '\n':
+ g_string_append_c (string, '\\');
+ g_string_append_c (string, 'n');
+ break;
+ case '\r':
+ g_string_append_c (string, '\\');
+ g_string_append_c (string, 'r');
+ break;
+ case '\t':
+ g_string_append_c (string, '\\');
+ g_string_append_c (string, 't');
+ break;
+ case '\v':
+ g_string_append_c (string, '\\');
+ g_string_append_c (string, 'v');
+ break;
+ default:
+ if (g_ascii_isprint(c)) {
+ g_string_append_c (string, (char) c);
+ } else if (i < b->length - 1 && g_ascii_isdigit(b->data[i + 1])) {
+ g_string_append_printf (string, "\\%03o", (guint) c);
+ } else {
+ g_string_append_printf (string, "\\%o",(guint) c);
+ }
+ break;
+ }
+ }
+
+ return g_string_free (string, FALSE);
+}
+
+static SwfdecBuffer *
+swfdec_buffer_from_string (const char *s)
+{
+ SwfdecBuffer *buffer;
+ GString *string;
+
+ g_return_val_if_fail (s != NULL, NULL);
+
+ string = g_string_new ("");
+
+ while (*s) {
+ if (*s == '\\') {
+ s++;
+ switch (*s) {
+ case '"':
+ g_string_append_c (string, '"');
+ break;
+ case '\'':
+ g_string_append_c (string, '\'');
+ break;
+ case '\\':
+ g_string_append_c (string, '\\');
+ break;
+ case 'f':
+ g_string_append_c (string, '\f');
+ break;
+ case 'n':
+ g_string_append_c (string, '\n');
+ break;
+ case 'r':
+ g_string_append_c (string, '\r');
+ break;
+ case 't':
+ g_string_append_c (string, '\t');
+ break;
+ case 'v':
+ g_string_append_c (string, '\v');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ guint val = s[0] - '0';
+ if (s[1] >= '0' && s[1] <= '7') {
+ s++;
+ val = 8 * val + s[0] - '0';
+ if (s[1] >= '0' && s[1] <= '7') {
+ s++;
+ val = 8 * val + s[0] - '0';
+ if (val >= 256) {
+ g_printerr ("Invalid octal escape sequence");
+ }
+ }
+ }
+ g_string_append_c (string, val);
+ }
+ break;
+ default:
+ g_printerr ("Stray \\ in string");
+ break;
+ }
+ } else {
+ g_string_append_c (string, *s);
+ }
+ s++;
+ }
+
+ buffer = swfdec_buffer_new_for_data ((guchar *) string->str, string->len);
+ g_string_free (string, FALSE);
+ return buffer;
+}
+
+typedef struct _RtmpState {
+ guint handshake;
+ SwfdecBufferQueue * send;
+ GHashTable * send_pending;
+ SwfdecBufferQueue * recv;
+ GHashTable * recv_pending;
+} RtmpState;
+
+static RtmpState *
+rtmp_state_new (void)
+{
+ RtmpState *state = g_slice_new0 (RtmpState);
+
+ state->handshake = 3;
+ state->send = swfdec_buffer_queue_new ();
+ state->send_pending = g_hash_table_new (g_direct_hash, g_direct_equal);
+ state->recv = swfdec_buffer_queue_new ();
+ state->recv_pending = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ return state;
+}
+
+static void
+rtmp_state_free (RtmpState *state)
+{
+ swfdec_buffer_queue_unref (state->send);
+ g_hash_table_destroy (state->send_pending);
+ swfdec_buffer_queue_unref (state->recv);
+ g_hash_table_destroy (state->recv_pending);
+ g_slice_free (RtmpState, state);
+}
+
+static void
+write_line (GPtrArray *lines, const char *type, SwfdecBuffer *buffer)
+{
+ char *s;
+
+ s = swfdec_buffer_to_string (buffer);
+ g_ptr_array_add (lines, g_strconcat (type, " ", s, NULL));
+ g_free (s);
+}
+
+static gboolean
+process_one_packet (GPtrArray *lines, const char *type,
+ GHashTable *lookup, SwfdecBufferQueue *queue, guint packet_size)
+{
+ SwfdecRtmpPacket *packet;
+ SwfdecRtmpHeader header = { 0, };
+ SwfdecBuffer *buffer;
+ SwfdecBits bits;
+ gsize header_size, i, remaining;
+
+ /* determine size of header */
+ buffer = swfdec_buffer_queue_peek (queue, 1);
+ if (buffer == NULL)
+ return FALSE;
+ header_size = swfdec_rtmp_header_peek_size (buffer->data[0]);
+ swfdec_buffer_unref (buffer);
+
+ /* read header */
+ buffer = swfdec_buffer_queue_peek (queue, header_size);
+ if (buffer == NULL)
+ return FALSE;
+ swfdec_bits_init (&bits, buffer);
+ i = swfdec_rtmp_header_peek_channel (&bits);
+ packet = g_hash_table_lookup (lookup, GUINT_TO_POINTER (i));
+ if (packet == NULL) {
+ packet = swfdec_rtmp_packet_new_empty ();
+ g_hash_table_insert (lookup, GUINT_TO_POINTER (i), packet);
+ } else {
+ swfdec_rtmp_header_copy (&header, &packet->header);
+ }
+ swfdec_rtmp_header_read (&header, &bits);
+ swfdec_buffer_unref (buffer);
+
+ /* read the data chunk */
+ remaining = GPOINTER_TO_SIZE (packet->buffer);
+ if (remaining) {
+ if (header_size >= 4) {
+ g_printerr ("not a continuation header, but old command not finished yet, dropping old command\n");
+ remaining = header.size;
+ }
+ } else {
+ remaining = header.size;
+ }
+ if (header_size + MIN (packet_size, remaining) > swfdec_buffer_queue_get_depth (queue))
+ return FALSE;
+
+ swfdec_rtmp_header_copy (&packet->header, &header);
+ if (remaining <= packet_size) {
+ packet->buffer = GSIZE_TO_POINTER (0);
+ } else {
+ packet->buffer = GSIZE_TO_POINTER (remaining - packet_size);
+ remaining = packet_size;
+ }
+
+ buffer = swfdec_buffer_queue_pull (queue, header_size + remaining);
+ g_assert (buffer);
+ write_line (lines, type, buffer);
+ return TRUE;
+}
+
+static void
+rtmp_process_send (RtmpState *state, GPtrArray *lines, SwfdecBuffer *buffer)
+{
+ swfdec_buffer_queue_push (state->send, buffer);
+
+ switch (state->handshake) {
+ case 0:
+ break;
+ case 1:
+ buffer = swfdec_buffer_queue_pull (state->send, 1536);
+ if (buffer == NULL)
+ return;
+ write_line (lines, "send", buffer);
+ state->handshake--;
+ break;
+ case 2:
+ g_printerr ("sent data when waiting for RTMP handshake reply?");
+ return;
+ case 3:
+ buffer = swfdec_buffer_queue_pull (state->send, 1537);
+ if (buffer) {
+ write_line (lines, "send", buffer);
+ state->handshake--;
+ }
+ return;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ while (process_one_packet (lines, "send", state->send_pending, state->send, 128))
+ ;
+}
+
+static void
+rtmp_process_recv (RtmpState *state, GPtrArray *lines, SwfdecBuffer *buffer)
+{
+ swfdec_buffer_queue_push (state->recv, buffer);
+
+ switch (state->handshake) {
+ case 0:
+ break;
+ case 1:
+ g_printerr ("received data when waiting for RTMP handshake data?");
+ return;
+ case 2:
+ buffer = swfdec_buffer_queue_pull (state->recv, 1536 * 2 + 1);
+ if (buffer) {
+ write_line (lines, "recv", buffer);
+ state->handshake--;
+ }
+ return;
+ case 3:
+ g_printerr ("received data when before sending?");
+ return;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ while (process_one_packet (lines, "recv", state->recv_pending, state->recv, 128))
+ ;
+}
+
+static char **
+rtmp_process (char **lines)
+{
+ GPtrArray *result;
+ RtmpState *state;
+ guint i;
+
+ result = g_ptr_array_new ();
+ state = rtmp_state_new ();
+ for (i = 0; lines[i] != NULL; i++) {
+ if (g_str_has_prefix (lines[i], "send ")) {
+ SwfdecBuffer *buffer = swfdec_buffer_from_string (lines[i] + 5);
+ rtmp_process_send (state, result, buffer);
+ } else if (g_str_has_prefix (lines[i], "recv ")) {
+ SwfdecBuffer *buffer = swfdec_buffer_from_string (lines[i] + 5);
+ rtmp_process_recv (state, result, buffer);
+ } else if (lines[i][0]) {
+ g_printerr ("ignoring line %u: %s\n", i + 1, lines[i]);
+ }
+ }
+ g_strfreev (lines);
+ g_ptr_array_add (result, g_strdup ("")); /* so we end with a newline */
+ g_ptr_array_add (result, NULL);
+ rtmp_state_free (state);
+
+ return (char **) g_ptr_array_free (result, FALSE);
+}
+
+int
+main (int argc, char **argv)
+{
+ GError *error = NULL;
+ char *contents;
+ char **lines;
+ GOptionEntry options[] = {
+ { NULL }
+ };
+ GOptionContext *ctx;
+
+ ctx = g_option_context_new ("");
+ g_option_context_add_main_entries (ctx, options, "options");
+ g_option_context_parse (ctx, &argc, &argv, &error);
+ g_option_context_free (ctx);
+
+ if (error) {
+ g_printerr ("Error parsing command line arguments: %s\n", error->message);
+ g_error_free (error);
+ return 1;
+ }
+ if (argc < 2) {
+ g_printerr ("Usage: %s [OPTIONS] infile [outfile]\n", argv[0]);
+ return 1;
+ }
+ if (!g_file_get_contents (argv[1], &contents, NULL, &error)) {
+ g_printerr ("Error opening file: %s\n", error->message);
+ g_error_free (error);
+ return 1;
+ }
+
+ lines = g_strsplit (contents, "\n", -1);
+ g_free (contents);
+
+
+ lines = rtmp_process (lines);
+
+
+ contents = g_strjoinv ("\n", lines);
+ g_strfreev (lines);
+ if (!g_file_set_contents (argc > 2 ? argv[2] : argv[1], contents, -1, &error)) {
+ g_printerr ("Error saving file: %s\n", error->message);
+ g_error_free (error);
+ return 1;
+ }
+ return 0;
+}
+
commit 7de8641576163e12e6adc7b3f178d81b3500ef66
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 17:58:48 2008 +0100
implement various properties of NetStream
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 36f12ee..b4cd38d 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -187,8 +187,6 @@ swfdec_net_stream_video_buffer_status (SwfdecNetStreamVideo *video, GParamSpec *
{
if (video->playing) {
swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Full);
- swfdec_audio_add (SWFDEC_AUDIO (stream->audio),
- SWFDEC_PLAYER (swfdec_gc_object_get_context (stream)));
} else {
swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Empty);
}
@@ -292,21 +290,40 @@ static void
swfdec_net_stream_get_audiocodec (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.audiocodec (get)");
+ SwfdecNetStream *stream;
+ SwfdecAudioStream *audio;
+
+ SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
+
+ audio = SWFDEC_AUDIO_STREAM (stream->audio);
+ if (audio->decoder) {
+ *rval = swfdec_as_value_from_integer (cx,
+ swfdec_audio_decoder_get_codec (audio->decoder));
+ } else {
+ *rval = swfdec_as_value_from_integer (cx, 0);
+ }
}
static void
swfdec_net_stream_get_bufferLength (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.bufferLength (get)");
+ SwfdecNetStream *stream;
+
+ SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
+
+ *rval = swfdec_as_value_from_number (cx, stream->video->next_length / 1000.);
}
static void
swfdec_net_stream_get_bufferTime (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.bufferTime (get)");
+ SwfdecNetStream *stream;
+
+ SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
+
+ *rval = swfdec_as_value_from_number (cx, stream->video->buffer_time / 1000.);
}
static void
@@ -359,7 +376,16 @@ static void
swfdec_net_stream_get_videocodec (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.videocodec (get)");
+ SwfdecNetStream *stream;
+
+ SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
+
+ if (stream->video->decoder) {
+ *rval = swfdec_as_value_from_integer (cx,
+ swfdec_video_decoder_get_codec (stream->video->decoder));
+ } else {
+ *rval = swfdec_as_value_from_integer (cx, 0);
+ }
}
static void
@@ -427,7 +453,7 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
}
static void
-swfdec_net_stream_send_buffer_time (SwfdecNetStream *stream)
+swfdec_net_stream_send_buffer_time (SwfdecNetStream *stream, guint buffer_time)
{
SwfdecRtmpPacket *packet;
SwfdecBots *bots;
@@ -436,7 +462,7 @@ swfdec_net_stream_send_buffer_time (SwfdecNetStream *stream)
bots = swfdec_bots_new ();
swfdec_bots_put_bu16 (bots, 3);
swfdec_bots_put_bu32 (bots, stream->stream);
- swfdec_bots_put_bu32 (bots, stream->video->buffer_time);
+ swfdec_bots_put_bu32 (bots, buffer_time);
buffer = swfdec_bots_close (bots);
packet = swfdec_rtmp_packet_new (2, 0, SWFDEC_RTMP_PACKET_PING, 0, buffer);
@@ -470,7 +496,7 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
packet->header.stream = stream->stream;
swfdec_rtmp_connection_send (stream->conn, packet);
}
- swfdec_net_stream_send_buffer_time (stream);
+ swfdec_net_stream_send_buffer_time (stream, 0);
}
SWFDEC_AS_NATIVE (2101, 202, swfdec_net_stream_send_connection)
commit 1b09c7057dfe93c0b42dcbe38c7374edda2e0a6b
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 17:57:01 2008 +0100
buffer time for videos is 100ms
even though a different number is sent if no setBufferTime has been
called on the NetStream object
diff --git a/swfdec/swfdec_net_stream_video.c b/swfdec/swfdec_net_stream_video.c
index e09b497..ccfddde 100644
--- a/swfdec/swfdec_net_stream_video.c
+++ b/swfdec/swfdec_net_stream_video.c
@@ -138,6 +138,7 @@ static void
swfdec_net_stream_video_init (SwfdecNetStreamVideo *video)
{
video->next = g_queue_new ();
+ video->buffer_time = 100;
}
SwfdecNetStreamVideo *
commit 627368625ac9a75970378ee14001f9e8f63ba674
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 17:56:37 2008 +0100
fix comment and whitespace
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 32364d2..01a71b3 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -138,7 +138,7 @@ next_packet:
if (packet->header.size == packet->buffer->length) {
SwfdecRtmpStream *stream;
SwfdecRtmpPacket *next;
-
+
stream = swfdec_rtmp_connection_get_stream (conn, packet->header.stream);
if (stream == NULL) {
swfdec_rtmp_packet_free (packet);
@@ -238,7 +238,7 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
swfdec_buffer_queue_flush (queue, header_size);
buffer = swfdec_buffer_queue_pull (queue, remaining);
g_assert (buffer);
- /* we allocate the buffer so it's big enough */
+ /* we allocated the buffer so we know it's big enough */
memcpy (packet->buffer->data + packet->buffer->length, buffer->data, remaining);
packet->buffer->length += remaining;
swfdec_buffer_unref (buffer);
commit c7c5df30e8cfc83a7c0d7f3e2f0c4fbfd8f12cbd
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 17:56:09 2008 +0100
add a getter for the codec
diff --git a/swfdec/swfdec_audio_decoder.c b/swfdec/swfdec_audio_decoder.c
index c1dbf60..efe4c2b 100644
--- a/swfdec/swfdec_audio_decoder.c
+++ b/swfdec/swfdec_audio_decoder.c
@@ -256,3 +256,10 @@ swfdec_audio_decoder_uses_format (SwfdecAudioDecoder *decoder, guint codec,
return decoder->codec == codec && decoder->format == format;
}
+guint
+swfdec_audio_decoder_get_codec (SwfdecAudioDecoder *decoder)
+{
+ g_return_val_if_fail (SWFDEC_IS_AUDIO_DECODER (decoder), 0);
+
+ return decoder->codec;
+}
diff --git a/swfdec/swfdec_audio_decoder.h b/swfdec/swfdec_audio_decoder.h
index ee72d3e..b3fdd1b 100644
--- a/swfdec/swfdec_audio_decoder.h
+++ b/swfdec/swfdec_audio_decoder.h
@@ -100,6 +100,8 @@ gboolean swfdec_audio_decoder_uses_format(SwfdecAudioDecoder * decoder,
guint codec,
SwfdecAudioFormat format);
+guint swfdec_audio_decoder_get_codec (SwfdecAudioDecoder * decoder);
+
/* for subclasses */
void swfdec_audio_decoder_error (SwfdecAudioDecoder * decoder,
const char * error,
commit 34e7c6e8484f5aa98d5832605366151a20f05afd
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 17:55:07 2008 +0100
remove liboil usage from swfdec_buffer.c
diff --git a/swfdec/swfdec_buffer.c b/swfdec/swfdec_buffer.c
index 3112f47..eef68f5 100644
--- a/swfdec/swfdec_buffer.c
+++ b/swfdec/swfdec_buffer.c
@@ -24,7 +24,6 @@
#endif
#include <swfdec_buffer.h>
-#include <liboil/liboil.h>
#include <glib.h>
#include <string.h>
#include <swfdec_debug.h>
@@ -491,7 +490,7 @@ swfdec_buffer_queue_peek (SwfdecBufferQueue * queue, gsize length)
while (offset < length) {
buffer = g->data;
amount = MIN (length - offset, buffer->length);
- oil_copy_u8 (newbuffer->data + offset, buffer->data, amount);
+ memcpy (newbuffer->data + offset, buffer->data, amount);
offset += amount;
g = g->next;
}
commit 5f3e329873605d95693da78ebae4ebe1e85673de
Author: Benjamin Otte <otte at gnome.org>
Date: Sat Dec 13 17:51:38 2008 +0100
remove unnecessary liboil includes
diff --git a/swfdec/swfdec_sound_matrix.c b/swfdec/swfdec_sound_matrix.c
index 5531a43..9c888a5 100644
--- a/swfdec/swfdec_sound_matrix.c
+++ b/swfdec/swfdec_sound_matrix.c
@@ -22,7 +22,6 @@
#endif
#include <swfdec_sound_matrix.h>
-#include <liboil/liboil.h>
#include <swfdec_debug.h>
void
diff --git a/swfdec/swfdec_swf_decoder.c b/swfdec/swfdec_swf_decoder.c
index 46e9960..f3cf0fb 100644
--- a/swfdec/swfdec_swf_decoder.c
+++ b/swfdec/swfdec_swf_decoder.c
@@ -27,7 +27,6 @@
#include <math.h>
#include <string.h>
#include <stdlib.h>
-#include <liboil/liboil.h>
#include "swfdec_swf_decoder.h"
#include "swfdec.h"
commit b9e870e4a5f05c8a9255d892c8bb2bba0aa6566c
Author: Benjamin Otte <otte at gnome.org>
Date: Fri Dec 12 11:06:37 2008 +0100
use glib functions here
diff --git a/test/swfdec_test_buffer.c b/test/swfdec_test_buffer.c
index 0443fb3..3750b00 100644
--- a/test/swfdec_test_buffer.c
+++ b/test/swfdec_test_buffer.c
@@ -21,7 +21,6 @@
#include "config.h"
#endif
-#include <ctype.h>
#include <string.h>
#include <unistd.h>
@@ -289,9 +288,9 @@ swfdec_test_buffer_toString (SwfdecAsContext *cx, SwfdecAsObject *object, guint
g_string_append_c (string, 'v');
break;
default:
- if (isprint(c)) {
+ if (g_ascii_isprint(c)) {
g_string_append_c (string, (char) c);
- } else if (i < b->length - 1 && isdigit(b->data[i + 1])) {
+ } else if (i < b->length - 1 && g_ascii_isdigit(b->data[i + 1])) {
g_string_append_printf (string, "\\%03o", (guint) c);
} else {
g_string_append_printf (string, "\\%o",(guint) c);
commit ba70044bb03ca68dc1b5dca07f89827b2a0641bb
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 23:13:04 2008 +0100
make NetStream output sound again
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 03fc1df..87f3534 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -43,7 +43,6 @@ libswfdec_source_files = \
$(CODEC_FILES) \
swfdec_audio_event.c \
swfdec_audio_load.c \
- swfdec_audio_flv.c \
swfdec_audio_stream.c \
swfdec_audio_swf_stream.c \
swfdec_bevel_filter.c \
@@ -119,6 +118,7 @@ libswfdec_source_files = \
swfdec_movie_clip_loader.c \
swfdec_net_connection.c \
swfdec_net_stream.c \
+ swfdec_net_stream_audio.c \
swfdec_net_stream_video.c \
swfdec_path.c \
swfdec_pattern.c \
@@ -268,7 +268,6 @@ noinst_HEADERS = \
swfdec_audio_decoder_gst.h \
swfdec_audio_decoder_uncompressed.h \
swfdec_audio_event.h \
- swfdec_audio_flv.h \
swfdec_audio_load.h \
swfdec_audio_stream.h \
swfdec_audio_swf_stream.h \
@@ -322,6 +321,7 @@ noinst_HEADERS = \
swfdec_movie.h \
swfdec_movie_clip_loader.h \
swfdec_net_stream.h \
+ swfdec_net_stream_audio.h \
swfdec_net_stream_video.h \
swfdec_path.h \
swfdec_pattern.h \
diff --git a/swfdec/swfdec_audio_flv.c b/swfdec/swfdec_audio_flv.c
deleted file mode 100644
index 4595f07..0000000
--- a/swfdec/swfdec_audio_flv.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Swfdec
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include "swfdec_audio_flv.h"
-#include "swfdec_debug.h"
-#include "swfdec_sound.h"
-
-
-G_DEFINE_TYPE (SwfdecAudioFlv, swfdec_audio_flv, SWFDEC_TYPE_AUDIO)
-
-static void
-swfdec_audio_flv_dispose (GObject *object)
-{
- SwfdecAudioFlv *flv = SWFDEC_AUDIO_FLV (object);
-
- if (flv->decoder != NULL) {
- g_object_unref (flv->decoder);
- flv->decoder = NULL;
- }
- g_queue_foreach (flv->playback_queue, (GFunc) swfdec_buffer_unref, NULL);
- g_queue_free (flv->playback_queue);
- g_object_unref (flv->flvdecoder);
-
- G_OBJECT_CLASS (swfdec_audio_flv_parent_class)->dispose (object);
-}
-
-static SwfdecBuffer *
-swfdec_audio_flv_decode_one (SwfdecAudioFlv *flv)
-{
- SwfdecBuffer *buffer;
- guint format;
- SwfdecAudioFormat in;
- guint now, soon;
-
- if (g_queue_is_empty (flv->playback_queue)) {
- /* sync */
- guint last;
- swfdec_flv_decoder_get_audio (flv->flvdecoder,
- SWFDEC_TICKS_TO_MSECS (flv->timestamp),
- NULL, NULL, &last, NULL);
- flv->playback_skip = SWFDEC_TICKS_TO_SAMPLES (
- flv->timestamp - SWFDEC_MSECS_TO_TICKS (last));
- flv->next_timestamp = last;
- SWFDEC_DEBUG ("syncing to %ums: next timestamp to decode is %ums, skipping %u samples",
- (guint) SWFDEC_TICKS_TO_MSECS (flv->timestamp),
- flv->next_timestamp, flv->playback_skip);
- }
- if (flv->decoder)
- buffer = swfdec_audio_decoder_pull (flv->decoder);
- else
- buffer = NULL;
- while (buffer == NULL) {
- if (flv->decoder && flv->next_timestamp == 0)
- return NULL;
- buffer = swfdec_flv_decoder_get_audio (flv->flvdecoder, flv->next_timestamp,
- &format, &in, &now, &soon);
-
- if (flv->next_timestamp != now) {
- /* FIXME: do sync on first frame here */
- SWFDEC_WARNING ("FIXME: didn't get requested timestamp - still loading?");
- }
- /* FIXME FIXME FIXME: This avoids decoding the last frame forever, however it ensures sync */
- if (soon == 0)
- return NULL;
- flv->next_timestamp = soon;
- if (flv->in == 0) {
- /* init */
- if (flv->decoder) {
- g_object_unref (flv->decoder);
- flv->decoder = NULL;
- }
- flv->format = format;
- flv->in = in;
- flv->decoder = swfdec_audio_decoder_new (flv->format, flv->in);
- if (flv->decoder == NULL)
- return NULL;
- /* This is a hack that ensures AAC codec data is always present, even if
- * the decoder gets initialized in the middle of the stream */
- if (format == SWFDEC_AUDIO_CODEC_AAC) {
- SwfdecBuffer *tmp = swfdec_flv_decoder_get_audio (flv->flvdecoder,
- 0, &format, NULL, NULL, NULL);
- if (format == SWFDEC_AUDIO_CODEC_AAC && tmp->data[0] == 0 &&
- tmp->length > 1) {
- tmp = swfdec_buffer_new_subbuffer (tmp, 1, tmp->length - 1);
- swfdec_audio_decoder_set_codec_data (flv->decoder, tmp);
- swfdec_buffer_unref (tmp);
- }
- }
- } else if (format != flv->format ||
- in != flv->in) {
- SWFDEC_ERROR ("FIXME: format change not implemented");
- return NULL;
- } else if (flv->decoder == NULL) {
- return NULL;
- }
- if (format == SWFDEC_AUDIO_CODEC_AAC) {
- SwfdecBuffer *data;
- SwfdecBits bits;
- guint type;
- swfdec_bits_init (&bits, buffer);
- type = swfdec_bits_get_u8 (&bits);
- switch (type) {
- case 0:
- data = swfdec_bits_get_buffer (&bits, -1);
- if (data) {
- swfdec_audio_decoder_set_codec_data (flv->decoder, data);
- swfdec_buffer_unref (data);
- }
- break;
- case 1:
- data = swfdec_bits_get_buffer (&bits, -1);
- if (data) {
- swfdec_audio_decoder_push (flv->decoder, data);
- swfdec_buffer_unref (data);
- } else {
- SWFDEC_ERROR ("no data in AAC data buffer?");
- }
- break;
- default:
- SWFDEC_FIXME ("handle AAC type %u", type);
- break;
- }
- } else {
- swfdec_audio_decoder_push (flv->decoder, buffer);
- }
- if (flv->next_timestamp == 0)
- swfdec_audio_decoder_push (flv->decoder, NULL);
- buffer = swfdec_audio_decoder_pull (flv->decoder);
- }
-
- g_queue_push_tail (flv->playback_queue, buffer);
- return buffer;
-}
-
-static gsize
-swfdec_audio_flv_render (SwfdecAudio *audio, gint16* dest,
- gsize start, gsize n_samples)
-{
- SwfdecAudioFlv *flv = SWFDEC_AUDIO_FLV (audio);
- GList *walk;
- gsize samples, rendered;
- SwfdecBuffer *buffer;
-
- g_assert (start < G_MAXINT);
- start += flv->playback_skip;
- SWFDEC_LOG ("flv %p rendering offset %"G_GSIZE_FORMAT", samples %"G_GSIZE_FORMAT,
- flv, start, n_samples);
- walk = g_queue_peek_head_link (flv->playback_queue);
- for (rendered = 0; rendered < n_samples;) {
- if (walk) {
- buffer = walk->data;
- walk = walk->next;
- } else {
- buffer = swfdec_audio_flv_decode_one (flv);
- if (!buffer)
- break;
- }
- samples = swfdec_sound_buffer_get_n_samples (buffer,
- swfdec_audio_format_new (44100, 2, TRUE));
- if (start) {
- if (samples <= start) {
- start -= samples;
- continue;
- }
- samples -= start;
- SWFDEC_LOG ("rendering %"G_GSIZE_FORMAT" samples, skipping %"G_GSIZE_FORMAT,
- samples, start);
- } else {
- SWFDEC_LOG ("rendering %"G_GSIZE_FORMAT" samples", samples);
- }
- samples = MIN (samples, n_samples - rendered);
- swfdec_sound_buffer_render (dest, buffer, start, samples);
- start = 0;
- rendered += samples;
- dest += 2 * samples;
- }
- return rendered;
-}
-
-static gsize
-swfdec_audio_flv_iterate (SwfdecAudio *audio, gsize remove)
-{
- SwfdecAudioFlv *flv = SWFDEC_AUDIO_FLV (audio);
- SwfdecBuffer *buffer;
- guint next;
-
- flv->playback_skip += remove;
- buffer = g_queue_peek_head (flv->playback_queue);
- while (buffer && flv->playback_skip >=
- swfdec_sound_buffer_get_n_samples (buffer, swfdec_audio_format_new (44100, 2, TRUE))
- + swfdec_audio_format_get_granularity (swfdec_audio_format_new (44100, 2, TRUE))) {
- buffer = g_queue_pop_head (flv->playback_queue);
- SWFDEC_LOG ("removing buffer with %u samples",
- swfdec_sound_buffer_get_n_samples (buffer, swfdec_audio_format_new (44100, 2, TRUE)));
- flv->playback_skip -= swfdec_sound_buffer_get_n_samples (buffer,
- swfdec_audio_format_new (44100, 2, TRUE));
- swfdec_buffer_unref (buffer);
- buffer = g_queue_peek_head (flv->playback_queue);
- }
- flv->timestamp += SWFDEC_SAMPLES_TO_TICKS (remove);
-
- if (!g_queue_is_empty (flv->playback_queue))
- return G_MAXUINT;
- swfdec_flv_decoder_get_audio (flv->flvdecoder,
- SWFDEC_TICKS_TO_MSECS (flv->timestamp),
- NULL, NULL, NULL, &next);
- return next ? G_MAXUINT : 0;
-}
-
-static void
-swfdec_audio_flv_class_init (SwfdecAudioFlvClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- SwfdecAudioClass *audio_class = SWFDEC_AUDIO_CLASS (klass);
-
- object_class->dispose = swfdec_audio_flv_dispose;
-
- audio_class->iterate = swfdec_audio_flv_iterate;
- audio_class->render = swfdec_audio_flv_render;
-}
-
-static void
-swfdec_audio_flv_init (SwfdecAudioFlv *flv)
-{
- flv->playback_queue = g_queue_new ();
-}
-
-SwfdecAudio *
-swfdec_audio_flv_new (SwfdecPlayer *player, SwfdecFlvDecoder *decoder, guint timestamp)
-{
- SwfdecAudioFlv *flv;
-
- flv = g_object_new (SWFDEC_TYPE_AUDIO_FLV, NULL);
-
- SWFDEC_DEBUG ("new audio flv for decoder %p, starting at %ums",
- decoder, timestamp);
- g_object_ref (decoder);
- flv->flvdecoder = decoder;
- flv->timestamp = SWFDEC_MSECS_TO_TICKS (timestamp);
- swfdec_audio_add (SWFDEC_AUDIO (flv), player);
-
- return SWFDEC_AUDIO (flv);
-}
-
diff --git a/swfdec/swfdec_audio_flv.h b/swfdec/swfdec_audio_flv.h
deleted file mode 100644
index 9ee2ca3..0000000
--- a/swfdec/swfdec_audio_flv.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Swfdec
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _SWFDEC_AUDIO_FLV_H_
-#define _SWFDEC_AUDIO_FLV_H_
-
-#include <swfdec/swfdec_audio_decoder.h>
-#include <swfdec/swfdec_audio_internal.h>
-#include <swfdec/swfdec_flv_decoder.h>
-
-G_BEGIN_DECLS
-
-typedef struct _SwfdecAudioFlv SwfdecAudioFlv;
-typedef struct _SwfdecAudioFlvClass SwfdecAudioFlvClass;
-
-#define SWFDEC_TYPE_AUDIO_FLV (swfdec_audio_flv_get_type())
-#define SWFDEC_IS_AUDIO_FLV(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_AUDIO_FLV))
-#define SWFDEC_IS_AUDIO_FLV_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_AUDIO_FLV))
-#define SWFDEC_AUDIO_FLV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_AUDIO_FLV, SwfdecAudioFlv))
-#define SWFDEC_AUDIO_FLV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_AUDIO_FLV, SwfdecAudioFlvClass))
-#define SWFDEC_AUDIO_FLV_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_AUDIO_FLV, SwfdecAudioFlvClass))
-
-struct _SwfdecAudioFlv
-{
- SwfdecAudio audio;
-
- SwfdecFlvDecoder * flvdecoder; /* decoder we play back */
- guint format; /* codec format of audio */
- gboolean width; /* width of audio */
- SwfdecAudioFormat in; /* input format of data */
- SwfdecAudioDecoder * decoder; /* decoder used for playback */
-
- SwfdecTick timestamp; /* current playback timestamp */
- guint next_timestamp; /* next timestamp in FLV file we request from */
- guint playback_skip; /* number of samples to skip at start of queue */
- GQueue * playback_queue; /* all the samples we've decoded so far */
-};
-
-struct _SwfdecAudioFlvClass
-{
- SwfdecAudioClass audio_class;
-};
-
-GType swfdec_audio_flv_get_type (void);
-
-SwfdecAudio * swfdec_audio_flv_new (SwfdecPlayer * player,
- SwfdecFlvDecoder * decoder,
- guint timestamp);
-
-G_END_DECLS
-#endif
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 04e82d5..36f12ee 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -27,6 +27,7 @@
#include "swfdec_as_internal.h"
#include "swfdec_as_strings.h"
#include "swfdec_debug.h"
+#include "swfdec_net_stream_audio.h"
#include "swfdec_net_stream_video.h"
#include "swfdec_sandbox.h"
#include "swfdec_rtmp_rpc.h"
@@ -81,6 +82,9 @@ swfdec_net_stream_rtmp_stream_receive (SwfdecRtmpStream *rtmp_stream,
SwfdecNetStream *stream = SWFDEC_NET_STREAM (rtmp_stream);
switch ((guint) header->type) {
+ case SWFDEC_RTMP_PACKET_AUDIO:
+ swfdec_net_stream_audio_push (stream->audio, swfdec_buffer_ref (buffer));
+ break;
case SWFDEC_RTMP_PACKET_VIDEO:
swfdec_net_stream_video_push (stream->video, header, buffer);
break;
@@ -140,6 +144,7 @@ swfdec_net_stream_rtmp_stream_flush (SwfdecRtmpStream *rtmp_stream)
{
SwfdecNetStream *stream = SWFDEC_NET_STREAM (rtmp_stream);
+ swfdec_net_stream_audio_push (stream->audio, NULL);
swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Flush);
}
@@ -180,8 +185,13 @@ static void
swfdec_net_stream_video_buffer_status (SwfdecNetStreamVideo *video, GParamSpec *pspec,
SwfdecNetStream* stream)
{
- swfdec_net_stream_onstatus (stream, video->playing ?
- SWFDEC_AS_STR_NetStream_Buffer_Full : SWFDEC_AS_STR_NetStream_Buffer_Empty);
+ if (video->playing) {
+ swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Full);
+ swfdec_audio_add (SWFDEC_AUDIO (stream->audio),
+ SWFDEC_PLAYER (swfdec_gc_object_get_context (stream)));
+ } else {
+ swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Empty);
+ }
}
static void
@@ -196,6 +206,10 @@ swfdec_net_stream_dispose (GObject *object)
g_signal_handlers_disconnect_by_func (stream->video,
swfdec_net_stream_video_buffer_status, stream);
g_object_unref (stream->video);
+ if (stream->audio) {
+ g_object_unref (stream->audio);
+ stream->audio = NULL;
+ }
G_OBJECT_CLASS (swfdec_net_stream_parent_class)->dispose (object);
}
@@ -404,6 +418,7 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream->conn = conn;
stream->rpc = swfdec_rtmp_rpc_new (conn, SWFDEC_AS_RELAY (stream));
stream->video = swfdec_net_stream_video_new (SWFDEC_PLAYER (cx));
+ stream->audio = swfdec_net_stream_audio_new (SWFDEC_PLAYER (cx));
g_object_ref (stream->video);
g_signal_connect (stream->video, "notify::playing",
G_CALLBACK (swfdec_net_stream_video_buffer_status), stream);
diff --git a/swfdec/swfdec_net_stream.h b/swfdec/swfdec_net_stream.h
index 4d1d3d2..12fc8ce 100644
--- a/swfdec/swfdec_net_stream.h
+++ b/swfdec/swfdec_net_stream.h
@@ -25,6 +25,7 @@
G_BEGIN_DECLS
/* forward decls */
+typedef struct _SwfdecNetStreamAudio SwfdecNetStreamAudio;
typedef struct _SwfdecNetStreamVideo SwfdecNetStreamVideo;
typedef struct _SwfdecNetStream SwfdecNetStream;
@@ -44,6 +45,7 @@ struct _SwfdecNetStream {
SwfdecRtmpRpc * rpc; /* rpc */
guint stream; /* id of this stream */
SwfdecNetStreamVideo * video; /* video object */
+ SwfdecNetStreamAudio * audio; /* video object */
};
struct _SwfdecNetStreamClass {
diff --git a/swfdec/swfdec_net_stream_audio.c b/swfdec/swfdec_net_stream_audio.c
new file mode 100644
index 0000000..893e728
--- /dev/null
+++ b/swfdec/swfdec_net_stream_audio.c
@@ -0,0 +1,112 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "swfdec_net_stream_audio.h"
+#include "swfdec_debug.h"
+#include "swfdec_sprite.h"
+#include "swfdec_tag.h"
+
+
+G_DEFINE_TYPE (SwfdecNetStreamAudio, swfdec_net_stream_audio, SWFDEC_TYPE_AUDIO_STREAM)
+
+static void
+swfdec_net_stream_audio_dispose (GObject *object)
+{
+ SwfdecNetStreamAudio *stream = SWFDEC_NET_STREAM_AUDIO (object);
+
+ if (stream->queue != NULL) {
+ /* pop eventual NULL buffer indicating end of data */
+ if (g_queue_peek_tail (stream->queue) == NULL)
+ g_queue_pop_tail (stream->queue);
+ g_queue_foreach (stream->queue, (GFunc) swfdec_buffer_unref, NULL);
+ g_queue_free (stream->queue);
+ stream->queue = NULL;
+ }
+
+ G_OBJECT_CLASS (swfdec_net_stream_audio_parent_class)->dispose (object);
+}
+
+static SwfdecBuffer *
+swfdec_net_stream_audio_pull (SwfdecAudioStream *audio)
+{
+ SwfdecNetStreamAudio *stream = SWFDEC_NET_STREAM_AUDIO (audio);
+ SwfdecBuffer *buffer, *result;
+ SwfdecAudioFormat format;
+ SwfdecBits bits;
+ guint codec;
+
+ if (g_queue_is_empty (stream->queue))
+ return NULL;
+
+ buffer = g_queue_pop_head (stream->queue);
+ if (buffer == NULL) {
+ swfdec_audio_stream_done (audio);
+ return NULL;
+ }
+
+ swfdec_bits_init (&bits, buffer);
+ codec = swfdec_bits_getbits (&bits, 4);
+ format = swfdec_audio_format_parse (&bits);
+ swfdec_audio_stream_use_decoder (audio, codec, format);
+ result = swfdec_bits_get_buffer (&bits, -1);
+ swfdec_buffer_unref (buffer);
+ return result;
+}
+
+static void
+swfdec_net_stream_audio_class_init (SwfdecNetStreamAudioClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ SwfdecAudioStreamClass *stream_class = SWFDEC_AUDIO_STREAM_CLASS (klass);
+
+ object_class->dispose = swfdec_net_stream_audio_dispose;
+
+ stream_class->pull = swfdec_net_stream_audio_pull;
+}
+
+static void
+swfdec_net_stream_audio_init (SwfdecNetStreamAudio *stream)
+{
+ stream->queue = g_queue_new ();
+}
+
+SwfdecNetStreamAudio *
+swfdec_net_stream_audio_new (SwfdecPlayer *player)
+{
+ SwfdecNetStreamAudio *stream;
+
+ g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
+
+ stream = g_object_new (SWFDEC_TYPE_NET_STREAM_AUDIO, NULL);
+
+ return stream;
+}
+
+void
+swfdec_net_stream_audio_push (SwfdecNetStreamAudio *audio, SwfdecBuffer *buffer)
+{
+ g_return_if_fail (SWFDEC_IS_NET_STREAM_AUDIO (audio));
+
+ g_queue_push_tail (audio->queue, buffer);
+}
diff --git a/swfdec/swfdec_net_stream_audio.h b/swfdec/swfdec_net_stream_audio.h
new file mode 100644
index 0000000..a4809b4
--- /dev/null
+++ b/swfdec/swfdec_net_stream_audio.h
@@ -0,0 +1,59 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SWFDEC_NET_STREAM_AUDIO_H_
+#define _SWFDEC_NET_STREAM_AUDIO_H_
+
+#include <swfdec/swfdec_audio_stream.h>
+#include <swfdec/swfdec_net_stream.h>
+
+G_BEGIN_DECLS
+
+//typedef struct _SwfdecNetStreamAudio SwfdecNetStreamAudio;
+typedef struct _SwfdecNetStreamAudioClass SwfdecNetStreamAudioClass;
+
+#define SWFDEC_TYPE_NET_STREAM_AUDIO (swfdec_net_stream_audio_get_type())
+#define SWFDEC_IS_NET_STREAM_AUDIO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_NET_STREAM_AUDIO))
+#define SWFDEC_IS_NET_STREAM_AUDIO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_NET_STREAM_AUDIO))
+#define SWFDEC_NET_STREAM_AUDIO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_NET_STREAM_AUDIO, SwfdecNetStreamAudio))
+#define SWFDEC_NET_STREAM_AUDIO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_NET_STREAM_AUDIO, SwfdecNetStreamAudioClass))
+#define SWFDEC_NET_STREAM_AUDIO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_NET_STREAM_AUDIO, SwfdecNetStreamAudioClass))
+
+struct _SwfdecNetStreamAudio
+{
+ SwfdecAudioStream stream;
+
+ GQueue * queue; /* not yet decoded buffers (NULL at the end means we're done) */
+};
+
+struct _SwfdecNetStreamAudioClass
+{
+ SwfdecAudioStreamClass stream_class;
+};
+
+GType swfdec_net_stream_audio_get_type (void);
+
+SwfdecNetStreamAudio * swfdec_net_stream_audio_new (SwfdecPlayer * player);
+
+void swfdec_net_stream_audio_push (SwfdecNetStreamAudio * audio,
+ SwfdecBuffer * buffer);
+
+
+G_END_DECLS
+#endif
commit 2d4a73f14d7b871fb63b3a367012c6202496e357
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 23:12:46 2008 +0100
fix likely bug with SoundStreamBlock before SoundStreamHead
diff --git a/swfdec/swfdec_audio_swf_stream.c b/swfdec/swfdec_audio_swf_stream.c
index 9a38753..83c1208 100644
--- a/swfdec/swfdec_audio_swf_stream.c
+++ b/swfdec/swfdec_audio_swf_stream.c
@@ -98,6 +98,11 @@ swfdec_audio_swf_stream_block (SwfdecAudioSwfStream *stream, SwfdecBuffer *buffe
guint n_samples;
int skip;
+ if (SWFDEC_AUDIO_STREAM (stream)->decoder == NULL) {
+ SWFDEC_ERROR ("SoundStreamBlock tag without SoundStreamHead");
+ return NULL;
+ }
+
swfdec_bits_init (&bits, buffer);
/* FIXME: we want accessor functions for this */
commit c877e9ded3889629656744be088304f50449f733
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 23:12:29 2008 +0100
allow buffering at the beginning of a stream
diff --git a/swfdec/swfdec_audio_stream.c b/swfdec/swfdec_audio_stream.c
index 857fecd..5eb0bfc 100644
--- a/swfdec/swfdec_audio_stream.c
+++ b/swfdec/swfdec_audio_stream.c
@@ -47,20 +47,16 @@ swfdec_audio_stream_dispose (GObject *object)
G_OBJECT_CLASS (swfdec_audio_stream_parent_class)->dispose (object);
}
-/* returns: number of samples available */
static void
swfdec_audio_stream_require (SwfdecAudioStream *stream, guint n_samples)
{
SwfdecAudioStreamClass *klass = SWFDEC_AUDIO_STREAM_GET_CLASS (stream);
SwfdecBuffer *buffer;
- /* subclasses are responsible for having set a proper decoder */
- g_assert (SWFDEC_IS_AUDIO_DECODER (stream->decoder));
-
while (stream->queue_size < n_samples && !stream->done) {
/* if the decoder still has data */
- buffer = swfdec_audio_decoder_pull (stream->decoder);
- if (buffer) {
+ if (stream->decoder &&
+ (buffer = swfdec_audio_decoder_pull (stream->decoder))) {
g_queue_push_tail (stream->queue, buffer);
stream->queue_size += buffer->length / 4;
continue;
@@ -71,6 +67,8 @@ swfdec_audio_stream_require (SwfdecAudioStream *stream, guint n_samples)
stream->buffering = TRUE;
break;
}
+ /* subclasses are responsible for having set a proper decoder */
+ g_assert (SWFDEC_IS_AUDIO_DECODER (stream->decoder));
swfdec_audio_decoder_push (stream->decoder, buffer);
swfdec_buffer_unref (buffer);
}
commit cd6cf7347a1702d055e68ad32449aea0ae687540
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 18:44:07 2008 +0100
fix wrong string in status messages
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index ca70ac3..04e82d5 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -50,7 +50,7 @@ swfdec_net_stream_onstatus (SwfdecNetStream *stream, const char *code)
SWFDEC_INFO ("emitting onStatus for %s", code);
SWFDEC_AS_VALUE_SET_STRING (&val, code);
swfdec_as_object_set_variable (object, SWFDEC_AS_STR_code, &val);
- SWFDEC_AS_VALUE_SET_STRING (&val, SWFDEC_AS_STR_level);
+ SWFDEC_AS_VALUE_SET_STRING (&val, SWFDEC_AS_STR_status);
swfdec_as_object_set_variable (object, SWFDEC_AS_STR_level, &val);
SWFDEC_AS_VALUE_SET_OBJECT (&val, object);
commit 4625422b186e863188a9425b5c076154c04eb926
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 18:14:27 2008 +0100
implement NetStream.time
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 67ccc83..ca70ac3 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -334,7 +334,11 @@ static void
swfdec_net_stream_get_time (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.time (get)");
+ SwfdecNetStream *stream;
+
+ SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
+
+ *rval = swfdec_as_value_from_number (cx, stream->video->time / 1000.);
}
static void
@@ -348,6 +352,8 @@ static void
swfdec_net_stream_install_properties (SwfdecAsObject *object)
{
object = object->prototype;
+ if (object == NULL)
+ return;
swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_audiocodec,
swfdec_net_stream_get_audiocodec, NULL);
diff --git a/swfdec/swfdec_net_stream_video.c b/swfdec/swfdec_net_stream_video.c
index 13fd14f..e09b497 100644
--- a/swfdec/swfdec_net_stream_video.c
+++ b/swfdec/swfdec_net_stream_video.c
@@ -137,7 +137,6 @@ swfdec_net_stream_video_class_init (SwfdecNetStreamVideoClass * g_class)
static void
swfdec_net_stream_video_init (SwfdecNetStreamVideo *video)
{
- video->buffer_time = 100;
video->next = g_queue_new ();
}
@@ -262,6 +261,7 @@ swfdec_net_stream_video_decode (SwfdecNetStreamVideo *video)
}
swfdec_net_stream_video_decode_one (video, packet->buffer);
video->next_length -= packet->header.timestamp;
+ video->time += packet->header.timestamp;
swfdec_rtmp_packet_free (packet);
}
}
@@ -269,6 +269,7 @@ swfdec_net_stream_video_decode (SwfdecNetStreamVideo *video)
static void
swfdec_net_stream_video_start (SwfdecNetStreamVideo *video)
{
+ video->time = 0;
video->playing = TRUE;
video->timeout.timestamp = SWFDEC_PLAYER (swfdec_gc_object_get_context (video))->priv->time;
g_object_notify (G_OBJECT (video), "playing");
diff --git a/swfdec/swfdec_net_stream_video.h b/swfdec/swfdec_net_stream_video.h
index 163d048..2aa5145 100644
--- a/swfdec/swfdec_net_stream_video.h
+++ b/swfdec/swfdec_net_stream_video.h
@@ -41,6 +41,7 @@ typedef struct _SwfdecNetStreamVideoClass SwfdecNetStreamVideoClass;
struct _SwfdecNetStreamVideo {
SwfdecGcObject object;
+ guint time; /* time as reported by NetStream.getTime() in ms */
gulong buffer_time; /* time to buffer before starting to play */
GQueue * next; /* queue of pending packets */
gulong next_length; /* number of milliseconds in the next queue */
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index e3dc013..e284208 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -356,6 +356,7 @@ swfdec_rtmp_connection_init (SwfdecRtmpConnection *conn)
conn->control_packets = g_queue_new ();
conn->rpc = swfdec_rtmp_rpc_new (conn, SWFDEC_AS_RELAY (conn));
+ conn->rpc->id = 1;
conn->read_size = SWFDEC_RTMP_BLOCK_SIZE;
conn->write_size = SWFDEC_RTMP_BLOCK_SIZE;
@@ -488,7 +489,7 @@ swfdec_rtmp_connection_send (SwfdecRtmpConnection *conn, SwfdecRtmpPacket *packe
g_assert (packet->header.size == packet->buffer->length);
packet->buffer->length = 0;
send = g_queue_is_empty (conn->packets);
- g_queue_push_tail (conn->packets, packet);
+ g_queue_push_head (conn->packets, packet);
SWFDEC_LOG ("pushed channel %u - %u packets now", packet->header.channel,
g_queue_get_length (conn->packets));
if (send)
commit c54d6df2ae2f605975b1cc56bf1ceafce118b19d
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 15:01:44 2008 +0100
stub out NetStream's native properties
diff --git a/swfdec/swfdec_as_strings.c b/swfdec/swfdec_as_strings.c
index 3df37a9..2385981 100644
--- a/swfdec/swfdec_as_strings.c
+++ b/swfdec/swfdec_as_strings.c
@@ -526,7 +526,7 @@ const SwfdecAsConstantStringValue swfdec_as_strings[] = {
SWFDEC_AS_CONSTANT_STRING ("currentFps")
SWFDEC_AS_CONSTANT_STRING ("decodedFrames")
SWFDEC_AS_CONSTANT_STRING ("liveDelay")
- SWFDEC_AS_CONSTANT_STRING ("videoCodec")
+ SWFDEC_AS_CONSTANT_STRING ("videocodec")
SWFDEC_AS_CONSTANT_STRING ("System")
SWFDEC_AS_CONSTANT_STRING ("__resolve")
SWFDEC_AS_CONSTANT_STRING ("Rectangle")
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index b28e166..67ccc83 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -195,6 +195,7 @@ swfdec_net_stream_dispose (GObject *object)
}
g_signal_handlers_disconnect_by_func (stream->video,
swfdec_net_stream_video_buffer_status, stream);
+ g_object_unref (stream->video);
G_OBJECT_CLASS (swfdec_net_stream_parent_class)->dispose (object);
}
@@ -273,6 +274,103 @@ swfdec_net_stream_set_checkPolicyFile (SwfdecAsContext *cx, SwfdecAsObject *obje
SWFDEC_STUB ("NetStream.checkPolicyFile (set)");
}
+static void
+swfdec_net_stream_get_audiocodec (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.audiocodec (get)");
+}
+
+static void
+swfdec_net_stream_get_bufferLength (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.bufferLength (get)");
+}
+
+static void
+swfdec_net_stream_get_bufferTime (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.bufferTime (get)");
+}
+
+static void
+swfdec_net_stream_get_bytesLoaded (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.bytesLoaded (get)");
+}
+
+static void
+swfdec_net_stream_get_bytesTotal (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.bytesTotal (get)");
+}
+
+static void
+swfdec_net_stream_get_currentFps (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.currentFps (get)");
+}
+
+static void
+swfdec_net_stream_get_decodedFrames (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.decodedFrames (get)");
+}
+
+static void
+swfdec_net_stream_get_liveDelay (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.liveDelay (get)");
+}
+
+static void
+swfdec_net_stream_get_time (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.time (get)");
+}
+
+static void
+swfdec_net_stream_get_videocodec (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
+{
+ SWFDEC_STUB ("NetStream.videocodec (get)");
+}
+
+static void
+swfdec_net_stream_install_properties (SwfdecAsObject *object)
+{
+ object = object->prototype;
+
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_audiocodec,
+ swfdec_net_stream_get_audiocodec, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_bufferLength,
+ swfdec_net_stream_get_bufferLength, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_bufferTime,
+ swfdec_net_stream_get_bufferTime, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_bytesLoaded,
+ swfdec_net_stream_get_bytesLoaded, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_bytesTotal,
+ swfdec_net_stream_get_bytesTotal, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_currentFps,
+ swfdec_net_stream_get_currentFps, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_decodedFrames,
+ swfdec_net_stream_get_decodedFrames, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_liveDelay,
+ swfdec_net_stream_get_liveDelay, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_time,
+ swfdec_net_stream_get_time, NULL);
+ swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_videocodec,
+ swfdec_net_stream_get_videocodec, NULL);
+}
+
SWFDEC_AS_NATIVE (2101, 200, swfdec_net_stream_construct)
void
swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
@@ -284,6 +382,8 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
SWFDEC_AS_CHECK (0, NULL, "oo", &o, &oconn);
+ swfdec_net_stream_install_properties (o);
+
if (!cx->frame->next || !cx->frame->next->construct)
return;
if (!SWFDEC_IS_RTMP_CONNECTION (oconn->relay))
@@ -298,6 +398,7 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream->conn = conn;
stream->rpc = swfdec_rtmp_rpc_new (conn, SWFDEC_AS_RELAY (stream));
stream->video = swfdec_net_stream_video_new (SWFDEC_PLAYER (cx));
+ g_object_ref (stream->video);
g_signal_connect (stream->video, "notify::playing",
G_CALLBACK (swfdec_net_stream_video_buffer_status), stream);
swfdec_as_context_get_time (cx, &stream->rpc->last_send);
commit bd504644cd5bfbb8be14bdfbdc8018052bec6207
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 13:40:53 2008 +0100
send a buffer time ping message after connecting
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 9fd98d0..b28e166 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -304,6 +304,24 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
}
+static void
+swfdec_net_stream_send_buffer_time (SwfdecNetStream *stream)
+{
+ SwfdecRtmpPacket *packet;
+ SwfdecBots *bots;
+ SwfdecBuffer *buffer;
+
+ bots = swfdec_bots_new ();
+ swfdec_bots_put_bu16 (bots, 3);
+ swfdec_bots_put_bu32 (bots, stream->stream);
+ swfdec_bots_put_bu32 (bots, stream->video->buffer_time);
+ buffer = swfdec_bots_close (bots);
+
+ packet = swfdec_rtmp_packet_new (2, 0, SWFDEC_RTMP_PACKET_PING, 0, buffer);
+ swfdec_buffer_unref (buffer);
+ swfdec_rtmp_connection_queue_control_packet (stream->conn, packet);
+}
+
SWFDEC_AS_NATIVE (2101, 201, swfdec_net_stream_onCreate)
void
swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
@@ -330,6 +348,7 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
packet->header.stream = stream->stream;
swfdec_rtmp_connection_send (stream->conn, packet);
}
+ swfdec_net_stream_send_buffer_time (stream);
}
SWFDEC_AS_NATIVE (2101, 202, swfdec_net_stream_send_connection)
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 83baf8d..e3dc013 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -37,11 +37,13 @@
/*** SwfdecRtmpStream ***/
-static void
-swfdec_rtmp_connection_push_control (SwfdecRtmpConnection *conn,
+void
+swfdec_rtmp_connection_queue_control_packet (SwfdecRtmpConnection *conn,
SwfdecRtmpPacket *packet)
{
+ g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
g_return_if_fail (packet->header.channel == 2);
+ g_return_if_fail (packet->header.stream == 0);
if (g_queue_is_empty (conn->control_packets)) {
g_queue_push_tail (conn->control_packets, NULL);
@@ -148,7 +150,7 @@ swfdec_rtmp_connection_handle_server_bandwidth (SwfdecRtmpConnection *conn,
org_header->timestamp - diff, buffer);
swfdec_buffer_unref (buffer);
- swfdec_rtmp_connection_push_control (conn, packet);
+ swfdec_rtmp_connection_queue_control_packet (conn, packet);
}
static void
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index 4d86cbd..38d916d 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -85,6 +85,9 @@ void swfdec_rtmp_connection_receive (SwfdecRtmpConnection * conn,
SwfdecBufferQueue * queue);
void swfdec_rtmp_connection_send (SwfdecRtmpConnection * conn,
SwfdecRtmpPacket * packet);
+void swfdec_rtmp_connection_queue_control_packet
+ (SwfdecRtmpConnection * conn,
+ SwfdecRtmpPacket * packet);
void swfdec_rtmp_connection_error (SwfdecRtmpConnection * conn,
const char * error,
commit f0225fd8b22676d3c5ee4436fe357290dba59165
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 12:51:57 2008 +0100
properly error our in NEtConnection.connect (null)
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 7af8bf7..83baf8d 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -372,7 +372,7 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
conn->socket = swfdec_rtmp_socket_new (conn, url);
conn->url = swfdec_url_copy (url);
} else {
- SWFDEC_FIXME ("handle NULL urls in connect()");
+ swfdec_rtmp_connection_error (conn, "handle NULL urls in connect()");
}
if (conn->error)
commit 4d1e0e4db4c6db9db0710f2a2cee7e3bff95c7ca
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 12:44:29 2008 +0100
handle Buffer.Full and Buffer.Empty messages
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 5d79cda..9fd98d0 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -177,6 +177,14 @@ swfdec_net_stream_mark (SwfdecGcObject *object)
}
static void
+swfdec_net_stream_video_buffer_status (SwfdecNetStreamVideo *video, GParamSpec *pspec,
+ SwfdecNetStream* stream)
+{
+ swfdec_net_stream_onstatus (stream, video->playing ?
+ SWFDEC_AS_STR_NetStream_Buffer_Full : SWFDEC_AS_STR_NetStream_Buffer_Empty);
+}
+
+static void
swfdec_net_stream_dispose (GObject *object)
{
SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
@@ -185,6 +193,8 @@ swfdec_net_stream_dispose (GObject *object)
swfdec_rtmp_rpc_free (stream->rpc);
stream->rpc = NULL;
}
+ g_signal_handlers_disconnect_by_func (stream->video,
+ swfdec_net_stream_video_buffer_status, stream);
G_OBJECT_CLASS (swfdec_net_stream_parent_class)->dispose (object);
}
@@ -288,6 +298,8 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream->conn = conn;
stream->rpc = swfdec_rtmp_rpc_new (conn, SWFDEC_AS_RELAY (stream));
stream->video = swfdec_net_stream_video_new (SWFDEC_PLAYER (cx));
+ g_signal_connect (stream->video, "notify::playing",
+ G_CALLBACK (swfdec_net_stream_video_buffer_status), stream);
swfdec_as_context_get_time (cx, &stream->rpc->last_send);
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
}
diff --git a/swfdec/swfdec_net_stream_video.c b/swfdec/swfdec_net_stream_video.c
index 8f72560..13fd14f 100644
--- a/swfdec/swfdec_net_stream_video.c
+++ b/swfdec/swfdec_net_stream_video.c
@@ -75,10 +75,31 @@ swfdec_net_stream_video_video_provider_init (SwfdecVideoProviderInterface *iface
/*** SWFDEC_NET_STREAM_VIDEO ***/
+enum {
+ PROP_0,
+ PROP_PLAYING
+};
+
G_DEFINE_TYPE_WITH_CODE (SwfdecNetStreamVideo, swfdec_net_stream_video, SWFDEC_TYPE_GC_OBJECT,
G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_VIDEO_PROVIDER, swfdec_net_stream_video_video_provider_init))
static void
+swfdec_net_stream_video_get_property (GObject *object, guint param_id, GValue *value,
+ GParamSpec * pspec)
+{
+ SwfdecNetStreamVideo *video = SWFDEC_NET_STREAM_VIDEO (object);
+
+ switch (param_id) {
+ case PROP_PLAYING:
+ g_value_set_boolean (value, video->playing);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
swfdec_net_stream_video_dispose (GObject *object)
{
SwfdecNetStreamVideo *video = SWFDEC_NET_STREAM_VIDEO (object);
@@ -106,11 +127,17 @@ swfdec_net_stream_video_class_init (SwfdecNetStreamVideoClass * g_class)
GObjectClass *object_class = G_OBJECT_CLASS (g_class);
object_class->dispose = swfdec_net_stream_video_dispose;
+ object_class->get_property = swfdec_net_stream_video_get_property;
+
+ g_object_class_install_property (object_class, PROP_PLAYING,
+ g_param_spec_boolean ("playing", "playing", "TRUE when the video is playing",
+ FALSE, G_PARAM_READABLE));
}
static void
swfdec_net_stream_video_init (SwfdecNetStreamVideo *video)
{
+ video->buffer_time = 100;
video->next = g_queue_new ();
}
@@ -221,8 +248,11 @@ swfdec_net_stream_video_decode (SwfdecNetStreamVideo *video)
for (;;) {
packet = g_queue_pop_head (video->next);
- if (packet == NULL)
+ if (packet == NULL) {
+ video->playing = FALSE;
+ g_object_notify (G_OBJECT (video), "playing");
return;
+ }
video->timeout.timestamp += SWFDEC_TICKS_PER_SECOND * packet->header.timestamp / 1000;
if (player->priv->time < video->timeout.timestamp) {
g_queue_push_head (video->next, packet);
@@ -231,6 +261,7 @@ swfdec_net_stream_video_decode (SwfdecNetStreamVideo *video)
return;
}
swfdec_net_stream_video_decode_one (video, packet->buffer);
+ video->next_length -= packet->header.timestamp;
swfdec_rtmp_packet_free (packet);
}
}
@@ -238,7 +269,9 @@ swfdec_net_stream_video_decode (SwfdecNetStreamVideo *video)
static void
swfdec_net_stream_video_start (SwfdecNetStreamVideo *video)
{
+ video->playing = TRUE;
video->timeout.timestamp = SWFDEC_PLAYER (swfdec_gc_object_get_context (video))->priv->time;
+ g_object_notify (G_OBJECT (video), "playing");
}
void
@@ -252,13 +285,11 @@ swfdec_net_stream_video_push (SwfdecNetStreamVideo *video,
packet = swfdec_rtmp_packet_new (header->channel, header->stream,
header->type, header->timestamp, buffer);
- if (g_queue_is_empty (video->next)) {
- g_queue_push_tail (video->next, packet);
- if (video->decoder == NULL)
- swfdec_net_stream_video_start (video);
+ g_queue_push_tail (video->next, packet);
+ video->next_length += header->timestamp;
+ if (!video->playing && video->next_length >= video->buffer_time) {
+ swfdec_net_stream_video_start (video);
swfdec_net_stream_video_decode (video);
- } else {
- g_queue_push_tail (video->next, packet);
}
}
diff --git a/swfdec/swfdec_net_stream_video.h b/swfdec/swfdec_net_stream_video.h
index ddd1ece..163d048 100644
--- a/swfdec/swfdec_net_stream_video.h
+++ b/swfdec/swfdec_net_stream_video.h
@@ -41,7 +41,10 @@ typedef struct _SwfdecNetStreamVideoClass SwfdecNetStreamVideoClass;
struct _SwfdecNetStreamVideo {
SwfdecGcObject object;
+ gulong buffer_time; /* time to buffer before starting to play */
GQueue * next; /* queue of pending packets */
+ gulong next_length; /* number of milliseconds in the next queue */
+ gboolean playing; /* TRUE if we're currently playing */
SwfdecTimeout timeout; /* time the next image should be decoded */
SwfdecVideoDecoder * decoder; /* the current decoder */
};
commit 673db3e51dfa13fde8f11f7305c6c8d9d7517dee
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 11:58:45 2008 +0100
emit NetStream.Buffer.Fluash onStatus message when told to flush
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index e74c5ff..5d79cda 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -25,6 +25,7 @@
#include "swfdec_as_frame_internal.h"
#include "swfdec_as_internal.h"
+#include "swfdec_as_strings.h"
#include "swfdec_debug.h"
#include "swfdec_net_stream_video.h"
#include "swfdec_sandbox.h"
@@ -36,6 +37,44 @@
#define SWFDEC_NET_STREAM_AUDIO_CHANNEL(stream) ((((stream)->stream - 1) * 5 % 65592) + 6)
static void
+swfdec_net_stream_onstatus (SwfdecNetStream *stream, const char *code)
+{
+ SwfdecAsValue val;
+ SwfdecAsObject *object;
+ SwfdecAsContext *cx;
+
+ cx = swfdec_gc_object_get_context (stream);
+ swfdec_sandbox_use (stream->conn->sandbox);
+
+ object = swfdec_as_object_new (cx, SWFDEC_AS_STR_Object, NULL);
+ SWFDEC_INFO ("emitting onStatus for %s", code);
+ SWFDEC_AS_VALUE_SET_STRING (&val, code);
+ swfdec_as_object_set_variable (object, SWFDEC_AS_STR_code, &val);
+ SWFDEC_AS_VALUE_SET_STRING (&val, SWFDEC_AS_STR_level);
+ swfdec_as_object_set_variable (object, SWFDEC_AS_STR_level, &val);
+
+ SWFDEC_AS_VALUE_SET_OBJECT (&val, object);
+ if (!swfdec_as_relay_call (SWFDEC_AS_RELAY (stream),
+ SWFDEC_AS_STR_onStatus, 1, &val, NULL)) {
+#if 0
+ // if it's an error message and the stream object didn't have onStatus
+ // handler, call System.onStatus
+ if (level == SWFDEC_AS_STR_error) {
+ SwfdecAsValue system;
+
+ swfdec_as_object_get_variable (cx->global,
+ SWFDEC_AS_STR_System, &system);
+ if (SWFDEC_AS_VALUE_IS_COMPOSITE (system) &&
+ (object = SWFDEC_AS_VALUE_GET_COMPOSITE (system)) != NULL) {
+ swfdec_as_object_call (object, SWFDEC_AS_STR_onStatus, 1, &val, NULL);
+ }
+ }
+#endif
+ }
+ swfdec_sandbox_unuse (stream->conn->sandbox);
+}
+
+static void
swfdec_net_stream_rtmp_stream_receive (SwfdecRtmpStream *rtmp_stream,
const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
{
@@ -97,9 +136,11 @@ swfdec_net_stream_rtmp_stream_sync (SwfdecRtmpStream *stream)
}
static void
-swfdec_net_stream_rtmp_stream_flush (SwfdecRtmpStream *stream)
+swfdec_net_stream_rtmp_stream_flush (SwfdecRtmpStream *rtmp_stream)
{
- SWFDEC_FIXME ("implement");
+ SwfdecNetStream *stream = SWFDEC_NET_STREAM (rtmp_stream);
+
+ swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Flush);
}
static void
commit 1ac6d8f50435d67786965bb7a0f2ff865ed7d034
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 11:51:03 2008 +0100
implement proper queueing for the RPC channel
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 0478d31..e74c5ff 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -70,12 +70,24 @@ swfdec_net_stream_rtmp_stream_receive (SwfdecRtmpStream *rtmp_stream,
}
static SwfdecRtmpPacket *
-swfdec_net_stream_rtmp_stream_sent (SwfdecRtmpStream *stream,
+swfdec_net_stream_rtmp_stream_sent (SwfdecRtmpStream *rtmp_stream,
const SwfdecRtmpPacket *packet)
{
- SWFDEC_FIXME ("implement");
+ SwfdecNetStream *stream = SWFDEC_NET_STREAM (rtmp_stream);
+ SwfdecRtmpPacket *result;
+
+ if (packet->header.channel == SWFDEC_NET_STREAM_RPC_CHANNEL (stream)) {
+ result = swfdec_rtmp_rpc_pop (stream->rpc, TRUE);
+ if (result) {
+ result->header.channel = SWFDEC_NET_STREAM_RPC_CHANNEL (stream);
+ result->header.stream = stream->stream;
+ }
+ } else {
+ result = NULL;
+ g_assert_not_reached ();
+ }
- return NULL;
+ return result;
}
static void
commit 282eea7488ef6b4e43b278438917218bb350e4e8
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 10 11:07:45 2008 +0100
stub out the ping messages
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 137b4ad..0478d31 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -73,14 +73,37 @@ static SwfdecRtmpPacket *
swfdec_net_stream_rtmp_stream_sent (SwfdecRtmpStream *stream,
const SwfdecRtmpPacket *packet)
{
+ SWFDEC_FIXME ("implement");
+
return NULL;
}
static void
+swfdec_net_stream_rtmp_stream_sync (SwfdecRtmpStream *stream)
+{
+ SWFDEC_FIXME ("implement");
+}
+
+static void
+swfdec_net_stream_rtmp_stream_flush (SwfdecRtmpStream *stream)
+{
+ SWFDEC_FIXME ("implement");
+}
+
+static void
+swfdec_net_stream_rtmp_stream_clear (SwfdecRtmpStream *stream)
+{
+ SWFDEC_FIXME ("implement");
+}
+
+static void
swfdec_net_stream_rtmp_stream_init (SwfdecRtmpStreamInterface *iface)
{
iface->receive = swfdec_net_stream_rtmp_stream_receive;
iface->sent = swfdec_net_stream_rtmp_stream_sent;
+ iface->sync = swfdec_net_stream_rtmp_stream_sync;
+ iface->flush = swfdec_net_stream_rtmp_stream_flush;
+ iface->clear = swfdec_net_stream_rtmp_stream_clear;
}
/*** NET STREAM ***/
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index c841484..7af8bf7 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -66,16 +66,57 @@ swfdec_rtmp_connection_handle_chunk_size (SwfdecRtmpConnection *conn, SwfdecBuff
}
}
+enum {
+ SWFDEC_RTMP_PING_SYNC = 0,
+ SWFDEC_RTMP_PING_FLUSH = 1,
+ SWFDEC_RTMP_PING_BUFFERTIME = 3,
+ SWFDEC_RTMP_PING_CLEAR = 4,
+ SWFDEC_RTMP_PING_PING = 6,
+ SWFDEC_RTMP_PING_PONG = 7
+};
+
static void
swfdec_rtmp_connection_handle_ping (SwfdecRtmpConnection *conn, SwfdecBuffer *buffer)
{
SwfdecBits bits;
guint type, target;
+ SwfdecRtmpStream *stream;
swfdec_bits_init (&bits, buffer);
type = swfdec_bits_get_bu16 (&bits);
target = swfdec_bits_get_bu32 (&bits);
- SWFDEC_FIXME ("handle ping type %u for target %u", type, target);
+ switch (type) {
+ case SWFDEC_RTMP_PING_SYNC:
+ stream = swfdec_rtmp_connection_get_stream (conn, target);
+ if (stream) {
+ swfdec_rtmp_stream_sync (stream);
+ } else {
+ SWFDEC_ERROR ("got sync ping for stream %u, but no such stream", target);
+ }
+ break;
+ case SWFDEC_RTMP_PING_FLUSH:
+ stream = swfdec_rtmp_connection_get_stream (conn, target);
+ if (stream) {
+ swfdec_rtmp_stream_flush (stream);
+ } else {
+ SWFDEC_ERROR ("got flush ping for stream %u, but no such stream", target);
+ }
+ break;
+ case SWFDEC_RTMP_PING_CLEAR:
+ stream = swfdec_rtmp_connection_get_stream (conn, target);
+ if (stream) {
+ swfdec_rtmp_stream_clear (stream);
+ } else {
+ SWFDEC_ERROR ("got clear ping for stream %u, but no such stream", target);
+ }
+ break;
+ case SWFDEC_RTMP_PING_BUFFERTIME:
+ case SWFDEC_RTMP_PING_PING:
+ case SWFDEC_RTMP_PING_PONG:
+ default:
+ SWFDEC_FIXME ("handle ping type %u for target %u", type, target);
+ break;
+ }
}
static void
@@ -203,10 +244,31 @@ swfdec_rtmp_connection_rtmp_stream_sent (SwfdecRtmpStream *stream,
}
static void
+swfdec_rtmp_connection_rtmp_stream_sync (SwfdecRtmpStream *stream)
+{
+ SWFDEC_FIXME ("implement");
+}
+
+static void
+swfdec_rtmp_connection_rtmp_stream_flush (SwfdecRtmpStream *stream)
+{
+ SWFDEC_FIXME ("implement");
+}
+
+static void
+swfdec_rtmp_connection_rtmp_stream_clear (SwfdecRtmpStream *stream)
+{
+ SWFDEC_FIXME ("implement");
+}
+
+static void
swfdec_rtmp_connection_rtmp_stream_init (SwfdecRtmpStreamInterface *iface)
{
iface->receive = swfdec_rtmp_connection_rtmp_stream_receive;
iface->sent = swfdec_rtmp_connection_rtmp_stream_sent;
+ iface->sync = swfdec_rtmp_connection_rtmp_stream_sync;
+ iface->flush = swfdec_rtmp_connection_rtmp_stream_flush;
+ iface->clear = swfdec_rtmp_connection_rtmp_stream_clear;
}
/*** SwfdecRtmpConnection ***/
@@ -403,6 +465,14 @@ swfdec_rtmp_connection_unregister_stream (SwfdecRtmpConnection *conn, guint id)
}
}
+SwfdecRtmpStream *
+swfdec_rtmp_connection_get_stream (SwfdecRtmpConnection *conn, guint id)
+{
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+
+ return g_hash_table_lookup (conn->streams, GUINT_TO_POINTER (id));
+}
+
void
swfdec_rtmp_connection_send (SwfdecRtmpConnection *conn, SwfdecRtmpPacket *packet)
{
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index ed0f323..4d86cbd 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -100,6 +100,8 @@ void swfdec_rtmp_connection_register_stream (SwfdecRtmpConnection * conn,
SwfdecRtmpStream * stream);
void swfdec_rtmp_connection_unregister_stream(SwfdecRtmpConnection * conn,
guint id);
+SwfdecRtmpStream * swfdec_rtmp_connection_get_stream (SwfdecRtmpConnection * conn,
+ guint id);
G_END_DECLS
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 7bacb34..32364d2 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -139,7 +139,7 @@ next_packet:
SwfdecRtmpStream *stream;
SwfdecRtmpPacket *next;
- stream = g_hash_table_lookup (conn->streams, GUINT_TO_POINTER (packet->header.stream));
+ stream = swfdec_rtmp_connection_get_stream (conn, packet->header.stream);
if (stream == NULL) {
swfdec_rtmp_packet_free (packet);
goto next_packet;
diff --git a/swfdec/swfdec_rtmp_stream.c b/swfdec/swfdec_rtmp_stream.c
index 4cb4595..590046b 100644
--- a/swfdec/swfdec_rtmp_stream.c
+++ b/swfdec/swfdec_rtmp_stream.c
@@ -86,3 +86,36 @@ swfdec_rtmp_stream_sent (SwfdecRtmpStream *stream, const SwfdecRtmpPacket *packe
iface = SWFDEC_RTMP_STREAM_GET_INTERFACE (stream);
return iface->sent (stream, packet);
}
+
+void
+swfdec_rtmp_stream_sync (SwfdecRtmpStream *stream)
+{
+ SwfdecRtmpStreamInterface *iface;
+
+ g_return_if_fail (SWFDEC_IS_RTMP_STREAM (stream));
+
+ iface = SWFDEC_RTMP_STREAM_GET_INTERFACE (stream);
+ iface->sync (stream);
+}
+
+void
+swfdec_rtmp_stream_flush (SwfdecRtmpStream *stream)
+{
+ SwfdecRtmpStreamInterface *iface;
+
+ g_return_if_fail (SWFDEC_IS_RTMP_STREAM (stream));
+
+ iface = SWFDEC_RTMP_STREAM_GET_INTERFACE (stream);
+ iface->flush (stream);
+}
+
+void
+swfdec_rtmp_stream_clear (SwfdecRtmpStream *stream)
+{
+ SwfdecRtmpStreamInterface *iface;
+
+ g_return_if_fail (SWFDEC_IS_RTMP_STREAM (stream));
+
+ iface = SWFDEC_RTMP_STREAM_GET_INTERFACE (stream);
+ iface->clear (stream);
+}
diff --git a/swfdec/swfdec_rtmp_stream.h b/swfdec/swfdec_rtmp_stream.h
index a700952..1aba25a 100644
--- a/swfdec/swfdec_rtmp_stream.h
+++ b/swfdec/swfdec_rtmp_stream.h
@@ -36,12 +36,16 @@ typedef struct _SwfdecRtmpStreamInterface SwfdecRtmpStreamInterface;
struct _SwfdecRtmpStreamInterface {
GTypeInterface parent;
- /* mandatory vfunc */
+ /* mandatory vfuncs */
void (* receive) (SwfdecRtmpStream * stream,
const SwfdecRtmpHeader * header,
SwfdecBuffer * buffer);
SwfdecRtmpPacket * (* sent) (SwfdecRtmpStream * stream,
const SwfdecRtmpPacket * packet);
+
+ void (* sync) (SwfdecRtmpStream * stream);
+ void (* flush) (SwfdecRtmpStream * stream);
+ void (* clear) (SwfdecRtmpStream * stream);
};
GType swfdec_rtmp_stream_get_type (void) G_GNUC_CONST;
@@ -51,6 +55,13 @@ void swfdec_rtmp_stream_receive (SwfdecRtmpStream * stream,
SwfdecRtmpPacket * swfdec_rtmp_stream_sent (SwfdecRtmpStream * stream,
const SwfdecRtmpPacket *packet);
+/* Ping type 0 */
+void swfdec_rtmp_stream_sync (SwfdecRtmpStream * stream);
+/* Ping type 1 */
+void swfdec_rtmp_stream_flush (SwfdecRtmpStream * stream);
+/* Ping type 4 */
+void swfdec_rtmp_stream_clear (SwfdecRtmpStream * stream);
+
G_END_DECLS
commit 09a4dee2e0ec10d198da7f810cab9d076b26954e
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 16 21:35:12 2008 +0100
make this thing play video again
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index fc65e9d..03fc1df 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -119,6 +119,7 @@ libswfdec_source_files = \
swfdec_movie_clip_loader.c \
swfdec_net_connection.c \
swfdec_net_stream.c \
+ swfdec_net_stream_video.c \
swfdec_path.c \
swfdec_pattern.c \
swfdec_player.c \
@@ -321,6 +322,7 @@ noinst_HEADERS = \
swfdec_movie.h \
swfdec_movie_clip_loader.h \
swfdec_net_stream.h \
+ swfdec_net_stream_video.h \
swfdec_path.h \
swfdec_pattern.h \
swfdec_player_internal.h \
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index b25bb38..137b4ad 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -26,6 +26,7 @@
#include "swfdec_as_frame_internal.h"
#include "swfdec_as_internal.h"
#include "swfdec_debug.h"
+#include "swfdec_net_stream_video.h"
#include "swfdec_sandbox.h"
#include "swfdec_rtmp_rpc.h"
#include "swfdec_rtmp_stream.h"
@@ -41,6 +42,9 @@ swfdec_net_stream_rtmp_stream_receive (SwfdecRtmpStream *rtmp_stream,
SwfdecNetStream *stream = SWFDEC_NET_STREAM (rtmp_stream);
switch ((guint) header->type) {
+ case SWFDEC_RTMP_PACKET_VIDEO:
+ swfdec_net_stream_video_push (stream->video, header, buffer);
+ break;
case SWFDEC_RTMP_PACKET_NOTIFY:
swfdec_sandbox_use (stream->conn->sandbox);
swfdec_rtmp_rpc_notify (stream->rpc, buffer);
@@ -90,7 +94,8 @@ swfdec_net_stream_mark (SwfdecGcObject *object)
SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
swfdec_gc_object_mark (stream->conn);
- /* no need to handle the channels, the connection manages them */
+ swfdec_rtmp_rpc_mark (stream->rpc);
+ swfdec_gc_object_mark (stream->video);
SWFDEC_GC_OBJECT_CLASS (swfdec_net_stream_parent_class)->mark (object);
}
@@ -206,6 +211,7 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream = g_object_new (SWFDEC_TYPE_NET_STREAM, "context", cx, NULL);
stream->conn = conn;
stream->rpc = swfdec_rtmp_rpc_new (conn, SWFDEC_AS_RELAY (stream));
+ stream->video = swfdec_net_stream_video_new (SWFDEC_PLAYER (cx));
swfdec_as_context_get_time (cx, &stream->rpc->last_send);
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
}
diff --git a/swfdec/swfdec_net_stream.h b/swfdec/swfdec_net_stream.h
index 6aed2f8..4d1d3d2 100644
--- a/swfdec/swfdec_net_stream.h
+++ b/swfdec/swfdec_net_stream.h
@@ -24,6 +24,8 @@
G_BEGIN_DECLS
+/* forward decls */
+typedef struct _SwfdecNetStreamVideo SwfdecNetStreamVideo;
typedef struct _SwfdecNetStream SwfdecNetStream;
typedef struct _SwfdecNetStreamClass SwfdecNetStreamClass;
@@ -41,6 +43,7 @@ struct _SwfdecNetStream {
SwfdecRtmpConnection * conn; /* the connection in use */
SwfdecRtmpRpc * rpc; /* rpc */
guint stream; /* id of this stream */
+ SwfdecNetStreamVideo * video; /* video object */
};
struct _SwfdecNetStreamClass {
diff --git a/swfdec/swfdec_net_stream_video.c b/swfdec/swfdec_net_stream_video.c
new file mode 100644
index 0000000..8f72560
--- /dev/null
+++ b/swfdec/swfdec_net_stream_video.c
@@ -0,0 +1,264 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "swfdec_net_stream_video.h"
+#include "swfdec_cached_video.h"
+#include "swfdec_debug.h"
+#include "swfdec_font.h"
+#include "swfdec_player_internal.h"
+#include "swfdec_renderer_internal.h"
+#include "swfdec_swf_decoder.h"
+
+/*** VIDEO PROVIDER INTERFACE ***/
+
+static cairo_surface_t *
+swfdec_net_stream_video_get_image (SwfdecVideoProvider *prov,
+ SwfdecRenderer *renderer, guint *width, guint *height)
+{
+ SwfdecNetStreamVideo *video = SWFDEC_NET_STREAM_VIDEO (prov);
+ cairo_surface_t *surface;
+
+ if (video->decoder == NULL)
+ return NULL;
+
+ surface = swfdec_video_decoder_get_image (video->decoder, renderer);
+ if (surface == NULL)
+ return NULL;
+
+ *width = swfdec_video_decoder_get_width (video->decoder);
+ *height = swfdec_video_decoder_get_height (video->decoder);
+ return surface;
+}
+
+static void
+swfdec_net_stream_video_get_size (SwfdecVideoProvider *prov, guint *width, guint *height)
+{
+ SwfdecNetStreamVideo *video = SWFDEC_NET_STREAM_VIDEO (prov);
+
+ if (video->decoder) {
+ *width = swfdec_video_decoder_get_width (video->decoder);
+ *height = swfdec_video_decoder_get_height (video->decoder);
+ } else {
+ *width = 0;
+ *height = 0;
+ }
+}
+
+static void
+swfdec_net_stream_video_video_provider_init (SwfdecVideoProviderInterface *iface)
+{
+ iface->get_image = swfdec_net_stream_video_get_image;
+ iface->get_size = swfdec_net_stream_video_get_size;
+}
+
+/*** SWFDEC_NET_STREAM_VIDEO ***/
+
+G_DEFINE_TYPE_WITH_CODE (SwfdecNetStreamVideo, swfdec_net_stream_video, SWFDEC_TYPE_GC_OBJECT,
+ G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_VIDEO_PROVIDER, swfdec_net_stream_video_video_provider_init))
+
+static void
+swfdec_net_stream_video_dispose (GObject *object)
+{
+ SwfdecNetStreamVideo *video = SWFDEC_NET_STREAM_VIDEO (object);
+
+ if (video->decoder != NULL) {
+ g_object_unref (video->decoder);
+ video->decoder = NULL;
+ }
+ if (video->next) {
+ g_queue_foreach (video->next, (GFunc) swfdec_rtmp_packet_free, NULL);
+ g_queue_free (video->next);
+ video->next = NULL;
+ }
+ if (video->timeout.callback) {
+ swfdec_player_remove_timeout (SWFDEC_PLAYER (swfdec_gc_object_get_context (video)),
+ &video->timeout);
+ }
+
+ G_OBJECT_CLASS (swfdec_net_stream_video_parent_class)->dispose (object);
+}
+
+static void
+swfdec_net_stream_video_class_init (SwfdecNetStreamVideoClass * g_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (g_class);
+
+ object_class->dispose = swfdec_net_stream_video_dispose;
+}
+
+static void
+swfdec_net_stream_video_init (SwfdecNetStreamVideo *video)
+{
+ video->next = g_queue_new ();
+}
+
+SwfdecNetStreamVideo *
+swfdec_net_stream_video_new (SwfdecPlayer *player)
+{
+ SwfdecNetStreamVideo *ret;
+
+ g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
+
+ ret = g_object_new (SWFDEC_TYPE_NET_STREAM_VIDEO, "context", player, NULL);
+
+ return ret;
+}
+
+static void
+swfdec_net_stream_video_decode_one (SwfdecNetStreamVideo *video, SwfdecBuffer *buffer)
+{
+ SwfdecBits bits;
+ guint frametype, codec;
+
+ swfdec_bits_init (&bits, buffer);
+ frametype = swfdec_bits_getbits (&bits, 4);
+ codec = swfdec_bits_getbits (&bits, 4);
+ if (video->decoder == NULL) {
+ video->decoder = swfdec_video_decoder_new (codec);
+ } else if (swfdec_video_decoder_get_codec (video->decoder) != codec) {
+ SWFDEC_WARNING ("codec change from %u to %u",
+ swfdec_video_decoder_get_codec (video->decoder), codec);
+ g_object_unref (video->decoder);
+ video->decoder = swfdec_video_decoder_new (codec);
+ }
+
+ if (codec == SWFDEC_VIDEO_CODEC_H264) {
+ guint type = swfdec_bits_get_u8 (&bits);
+ /* composition_time_offset = */ swfdec_bits_get_bu24 (&bits);
+ switch (type) {
+ case 0:
+ buffer = swfdec_bits_get_buffer (&bits, -1);
+ if (buffer) {
+ swfdec_video_decoder_set_codec_data (video->decoder, buffer);
+ swfdec_buffer_unref (buffer);
+ }
+ break;
+ case 1:
+ buffer = swfdec_bits_get_buffer (&bits, -1);
+ if (buffer) {
+ swfdec_video_decoder_decode (video->decoder, buffer);
+ } else {
+ SWFDEC_ERROR ("no data in H264 buffer?");
+ }
+ swfdec_video_provider_new_image (SWFDEC_VIDEO_PROVIDER (video));
+ break;
+ case 2:
+ break;
+ default:
+ SWFDEC_ERROR ("H264 data type %u not supported", type);
+ break;
+ }
+ } else if (codec == SWFDEC_VIDEO_CODEC_VP6 ||
+ codec == SWFDEC_VIDEO_CODEC_VP6_ALPHA) {
+ /* FIXME: This is somewhat nasty as we modify values in the decoder
+ * directly. I know the current decoders don't mind, but if we expose
+ * the decoder API... */
+ guint wsub, hsub;
+ wsub = swfdec_bits_getbits (&bits, 4);
+ hsub = swfdec_bits_getbits (&bits, 4);
+ buffer = swfdec_bits_get_buffer (&bits, -1);
+ swfdec_video_decoder_decode (video->decoder, buffer);
+ swfdec_buffer_unref (buffer);
+ if (hsub >= video->decoder->height || wsub >= video->decoder->width) {
+ SWFDEC_ERROR ("can't reduce size by more than available");
+ video->decoder->width = 0;
+ video->decoder->height = 0;
+ } else {
+ video->decoder->width -= wsub;
+ video->decoder->height -= hsub;
+ }
+ swfdec_video_provider_new_image (SWFDEC_VIDEO_PROVIDER (video));
+ } else {
+ buffer = swfdec_bits_get_buffer (&bits, -1);
+ swfdec_video_decoder_decode (video->decoder, buffer);
+ swfdec_buffer_unref (buffer);
+ swfdec_video_provider_new_image (SWFDEC_VIDEO_PROVIDER (video));
+ }
+}
+
+static void swfdec_net_stream_video_decode (SwfdecNetStreamVideo *video);
+static void
+swfdec_net_stream_video_timeout (SwfdecTimeout *timeout)
+{
+ SwfdecNetStreamVideo *video = SWFDEC_NET_STREAM_VIDEO ((void *) ((guint8 *) timeout - G_STRUCT_OFFSET (SwfdecNetStreamVideo, timeout)));
+ SwfdecRtmpPacket *packet;
+
+ video->timeout.callback = NULL;
+ /* subtract time, so swfdec_net_stream_video_decode() can do its work */
+ packet = g_queue_peek_head (video->next);
+ g_assert (packet);
+ video->timeout.timestamp -= SWFDEC_TICKS_PER_SECOND * packet->header.timestamp / 1000;
+ swfdec_net_stream_video_decode (video);
+}
+
+static void
+swfdec_net_stream_video_decode (SwfdecNetStreamVideo *video)
+{
+ SwfdecPlayer *player = SWFDEC_PLAYER (swfdec_gc_object_get_context (video));
+ SwfdecRtmpPacket *packet;
+
+ for (;;) {
+ packet = g_queue_pop_head (video->next);
+ if (packet == NULL)
+ return;
+ video->timeout.timestamp += SWFDEC_TICKS_PER_SECOND * packet->header.timestamp / 1000;
+ if (player->priv->time < video->timeout.timestamp) {
+ g_queue_push_head (video->next, packet);
+ video->timeout.callback = swfdec_net_stream_video_timeout;
+ swfdec_player_add_timeout (player, &video->timeout);
+ return;
+ }
+ swfdec_net_stream_video_decode_one (video, packet->buffer);
+ swfdec_rtmp_packet_free (packet);
+ }
+}
+
+static void
+swfdec_net_stream_video_start (SwfdecNetStreamVideo *video)
+{
+ video->timeout.timestamp = SWFDEC_PLAYER (swfdec_gc_object_get_context (video))->priv->time;
+}
+
+void
+swfdec_net_stream_video_push (SwfdecNetStreamVideo *video,
+ const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
+{
+ SwfdecRtmpPacket *packet;
+
+ g_return_if_fail (SWFDEC_IS_NET_STREAM_VIDEO (video));
+ g_return_if_fail (packet != NULL);
+
+ packet = swfdec_rtmp_packet_new (header->channel, header->stream,
+ header->type, header->timestamp, buffer);
+ if (g_queue_is_empty (video->next)) {
+ g_queue_push_tail (video->next, packet);
+ if (video->decoder == NULL)
+ swfdec_net_stream_video_start (video);
+ swfdec_net_stream_video_decode (video);
+ } else {
+ g_queue_push_tail (video->next, packet);
+ }
+}
+
diff --git a/swfdec/swfdec_net_stream_video.h b/swfdec/swfdec_net_stream_video.h
new file mode 100644
index 0000000..ddd1ece
--- /dev/null
+++ b/swfdec/swfdec_net_stream_video.h
@@ -0,0 +1,63 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SWFDEC_NET_STREAM_VIDEO_H_
+#define _SWFDEC_NET_STREAM_VIDEO_H_
+
+#include <swfdec/swfdec_gc_object.h>
+#include <swfdec/swfdec_net_stream.h>
+#include <swfdec/swfdec_player_internal.h>
+#include <swfdec/swfdec_rtmp_header.h>
+#include <swfdec/swfdec_video_decoder.h>
+#include <swfdec/swfdec_video_provider.h>
+
+G_BEGIN_DECLS
+
+//typedef struct _SwfdecNetStreamVideo SwfdecNetStreamVideo;
+typedef struct _SwfdecNetStreamVideoClass SwfdecNetStreamVideoClass;
+
+#define SWFDEC_TYPE_NET_STREAM_VIDEO (swfdec_net_stream_video_get_type())
+#define SWFDEC_IS_NET_STREAM_VIDEO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_NET_STREAM_VIDEO))
+#define SWFDEC_IS_NET_STREAM_VIDEO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_NET_STREAM_VIDEO))
+#define SWFDEC_NET_STREAM_VIDEO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_NET_STREAM_VIDEO, SwfdecNetStreamVideo))
+#define SWFDEC_NET_STREAM_VIDEO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_NET_STREAM_VIDEO, SwfdecNetStreamVideoClass))
+
+struct _SwfdecNetStreamVideo {
+ SwfdecGcObject object;
+
+ GQueue * next; /* queue of pending packets */
+ SwfdecTimeout timeout; /* time the next image should be decoded */
+ SwfdecVideoDecoder * decoder; /* the current decoder */
+};
+
+struct _SwfdecNetStreamVideoClass {
+ SwfdecGcObjectClass object_class;
+};
+
+GType swfdec_net_stream_video_get_type (void);
+
+SwfdecNetStreamVideo * swfdec_net_stream_video_new (SwfdecPlayer * player);
+
+void swfdec_net_stream_video_push (SwfdecNetStreamVideo * video,
+ const SwfdecRtmpHeader *header,
+ SwfdecBuffer * buffer);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_video_movie_as.c b/swfdec/swfdec_video_movie_as.c
index d14cbb4..d8d12d7 100644
--- a/swfdec/swfdec_video_movie_as.c
+++ b/swfdec/swfdec_video_movie_as.c
@@ -25,6 +25,7 @@
#include "swfdec_as_internal.h"
#include "swfdec_as_strings.h"
#include "swfdec_debug.h"
+#include "swfdec_net_stream.h"
#include "swfdec_player_internal.h"
#include "swfdec_sandbox.h"
@@ -38,13 +39,15 @@ swfdec_video_attach_video (SwfdecAsContext *cx, SwfdecAsObject *object,
SWFDEC_AS_CHECK (SWFDEC_TYPE_VIDEO_MOVIE, &video, "O", &o);
- if (o == NULL || !SWFDEC_IS_VIDEO_PROVIDER (o->relay)) {
+ if (o == NULL) {
+ swfdec_video_movie_set_provider (video, NULL);
+ } else if (SWFDEC_IS_NET_STREAM (o->relay)) {
+ swfdec_video_movie_set_provider (video,
+ SWFDEC_VIDEO_PROVIDER (SWFDEC_NET_STREAM (o->relay)->video));
+ } else {
SWFDEC_WARNING ("calling attachVideo without a NetStream object");
swfdec_video_movie_set_provider (video, NULL);
- return;
}
-
- swfdec_video_movie_set_provider (video, SWFDEC_VIDEO_PROVIDER (o->relay));
}
SWFDEC_AS_NATIVE (667, 2, swfdec_video_clear)
commit 306097367ab3c53d65a5d3e8eaee50a233144813
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 16 21:34:12 2008 +0100
make various errors in the screen decoder not fatal
diff --git a/swfdec/swfdec_video_decoder_screen.c b/swfdec/swfdec_video_decoder_screen.c
index 42504b5..08c725e 100644
--- a/swfdec/swfdec_video_decoder_screen.c
+++ b/swfdec/swfdec_video_decoder_screen.c
@@ -55,7 +55,7 @@ swfdec_video_decoder_screen_decode (SwfdecVideoDecoder *dec, SwfdecBuffer *buffe
h = swfdec_bits_getbits (&bits, 12);
if (dec->width == 0 || dec->height == 0) {
if (w == 0 || h == 0) {
- swfdec_video_decoder_error (dec, "width or height is 0: %ux%u", w, h);
+ SWFDEC_ERROR ("width or height is 0: %ux%u", w, h);
return;
}
/* check for overflow */
@@ -72,7 +72,7 @@ swfdec_video_decoder_screen_decode (SwfdecVideoDecoder *dec, SwfdecBuffer *buffe
dec->height = h;
dec->rowstride[0] = w * 4;
} else if (dec->width != w || dec->height != h) {
- swfdec_video_decoder_error (dec, "width or height differ from original: was %ux%u, is %ux%u",
+ SWFDEC_ERROR ("width or height differ from original: was %ux%u, is %ux%u",
dec->width, dec->height, w, h);
/* FIXME: this is what ffmpeg does, should we be more forgiving? */
return;
commit e5e3f15d026b3774b44fccf5c9b5f2fc2f960275
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 9 19:06:34 2008 +0100
handle notify calls
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 02c33cc..b25bb38 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -41,6 +41,11 @@ swfdec_net_stream_rtmp_stream_receive (SwfdecRtmpStream *rtmp_stream,
SwfdecNetStream *stream = SWFDEC_NET_STREAM (rtmp_stream);
switch ((guint) header->type) {
+ case SWFDEC_RTMP_PACKET_NOTIFY:
+ swfdec_sandbox_use (stream->conn->sandbox);
+ swfdec_rtmp_rpc_notify (stream->rpc, buffer);
+ swfdec_sandbox_unuse (stream->conn->sandbox);
+ break;
case SWFDEC_RTMP_PACKET_INVOKE:
swfdec_sandbox_use (stream->conn->sandbox);
if (swfdec_rtmp_rpc_receive (stream->rpc, buffer)) {
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index f11fdbf..c841484 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -142,6 +142,11 @@ swfdec_rtmp_connection_rtmp_stream_receive (SwfdecRtmpStream *stream,
case SWFDEC_RTMP_PACKET_CLIENT_BANDWIDTH:
swfdec_rtmp_connection_handle_client_bandwidth (conn, buffer);
break;
+ case SWFDEC_RTMP_PACKET_NOTIFY:
+ swfdec_sandbox_use (conn->sandbox);
+ swfdec_rtmp_rpc_notify (conn->rpc, buffer);
+ swfdec_sandbox_unuse (conn->sandbox);
+ break;
case SWFDEC_RTMP_PACKET_INVOKE:
swfdec_sandbox_use (conn->sandbox);
if (swfdec_rtmp_rpc_receive (conn->rpc, buffer)) {
diff --git a/swfdec/swfdec_rtmp_rpc.c b/swfdec/swfdec_rtmp_rpc.c
index e539bde..bf8a2cd 100644
--- a/swfdec/swfdec_rtmp_rpc.c
+++ b/swfdec/swfdec_rtmp_rpc.c
@@ -192,6 +192,9 @@ swfdec_rtmp_rpc_receive (SwfdecRtmpRpc *rpc, SwfdecBuffer *buffer)
SwfdecBits bits;
gboolean result;
+ g_return_val_if_fail (rpc != NULL, FALSE);
+ g_return_val_if_fail (buffer != NULL, FALSE);
+
context = swfdec_gc_object_get_context (rpc->conn);
cx = swfdec_amf_context_new (context);
g_assert (context->global);
@@ -217,6 +220,49 @@ swfdec_rtmp_rpc_receive (SwfdecRtmpRpc *rpc, SwfdecBuffer *buffer)
return result;
}
+void
+swfdec_rtmp_rpc_notify (SwfdecRtmpRpc *rpc, SwfdecBuffer *buffer)
+{
+ SwfdecAsContext *context;
+ SwfdecAmfContext *cx;
+ SwfdecAsValue *args;
+ SwfdecAsValue name;
+ SwfdecBits bits;
+ guint i;
+
+ g_return_if_fail (rpc != NULL);
+ g_return_if_fail (buffer != NULL);
+
+ context = swfdec_gc_object_get_context (rpc->conn);
+ cx = swfdec_amf_context_new (context);
+ g_assert (context->global);
+ swfdec_bits_init (&bits, buffer);
+
+ if (!swfdec_amf_decode (cx, &bits, &name)) {
+ SWFDEC_ERROR ("could not decode name");
+ return;
+ }
+
+ args = NULL;
+ for (i = 0; swfdec_bits_left (&bits); i++) {
+ if ((i % 4) == 0)
+ args = g_realloc (args, sizeof (SwfdecAsValue) * (i + 4));
+
+ if (!swfdec_amf_decode (cx, &bits, &args[i])) {
+ SWFDEC_ERROR ("could not decode argument %u", i);
+ return;
+ }
+ }
+ swfdec_as_relay_call (rpc->target, swfdec_as_value_to_string (context, name),
+ i, args, NULL);
+ g_free (args);
+
+ swfdec_amf_context_free (cx);
+ if (swfdec_bits_left (&bits)) {
+ SWFDEC_FIXME ("%u bytes left after invoke", swfdec_bits_left (&bits) / 8);
+ }
+}
+
SwfdecRtmpPacket *
swfdec_rtmp_rpc_pop (SwfdecRtmpRpc *rpc, gboolean pull_if_pending)
{
diff --git a/swfdec/swfdec_rtmp_rpc.h b/swfdec/swfdec_rtmp_rpc.h
index 3ca46e6..f7d1a79 100644
--- a/swfdec/swfdec_rtmp_rpc.h
+++ b/swfdec/swfdec_rtmp_rpc.h
@@ -57,6 +57,8 @@ void swfdec_rtmp_rpc_send (SwfdecRtmpRpc * rpc,
const SwfdecAsValue * argv);
gboolean swfdec_rtmp_rpc_receive (SwfdecRtmpRpc * rpc,
SwfdecBuffer * buffer);
+void swfdec_rtmp_rpc_notify (SwfdecRtmpRpc * rpc,
+ SwfdecBuffer * buffer);
G_END_DECLS
commit 31ee9ceb97360f10595678b76bad7d29700f9fcf
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 9 18:52:02 2008 +0100
add forgotten files (ooops)
diff --git a/swfdec/swfdec_rtmp_stream.c b/swfdec/swfdec_rtmp_stream.c
new file mode 100644
index 0000000..4cb4595
--- /dev/null
+++ b/swfdec/swfdec_rtmp_stream.c
@@ -0,0 +1,88 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_rtmp_stream.h"
+#include "swfdec_debug.h"
+#include "swfdec_loader_internal.h"
+#include "swfdec_player_internal.h"
+
+static void
+swfdec_rtmp_stream_base_init (gpointer g_class)
+{
+ static gboolean initialized = FALSE;
+
+ if (G_UNLIKELY (!initialized)) {
+ initialized = TRUE;
+ }
+}
+
+GType
+swfdec_rtmp_stream_get_type (void)
+{
+ static GType rtmp_stream_type = 0;
+
+ if (!rtmp_stream_type) {
+ static const GTypeInfo rtmp_stream_info = {
+ sizeof (SwfdecRtmpStreamInterface),
+ swfdec_rtmp_stream_base_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ };
+
+ rtmp_stream_type = g_type_register_static (G_TYPE_INTERFACE,
+ "SwfdecRtmpStream", &rtmp_stream_info, 0);
+ g_type_interface_add_prerequisite (rtmp_stream_type, G_TYPE_OBJECT);
+ }
+
+ return rtmp_stream_type;
+}
+
+void
+swfdec_rtmp_stream_receive (SwfdecRtmpStream *stream, const SwfdecRtmpPacket *packet)
+{
+ SwfdecRtmpStreamInterface *iface;
+
+ g_return_if_fail (SWFDEC_IS_RTMP_STREAM (stream));
+ g_return_if_fail (packet != NULL);
+
+ iface = SWFDEC_RTMP_STREAM_GET_INTERFACE (stream);
+ g_assert (iface->receive != NULL);
+ return iface->receive (stream, &packet->header, packet->buffer);
+}
+
+SwfdecRtmpPacket *
+swfdec_rtmp_stream_sent (SwfdecRtmpStream *stream, const SwfdecRtmpPacket *packet)
+{
+ SwfdecRtmpStreamInterface *iface;
+
+ g_return_val_if_fail (SWFDEC_IS_RTMP_STREAM (stream), NULL);
+ g_return_val_if_fail (packet != NULL, NULL);
+
+ iface = SWFDEC_RTMP_STREAM_GET_INTERFACE (stream);
+ return iface->sent (stream, packet);
+}
diff --git a/swfdec/swfdec_rtmp_stream.h b/swfdec/swfdec_rtmp_stream.h
new file mode 100644
index 0000000..a700952
--- /dev/null
+++ b/swfdec/swfdec_rtmp_stream.h
@@ -0,0 +1,57 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SWFDEC_RTMP_STREAM_H__
+#define __SWFDEC_RTMP_STREAM_H__
+
+#include <swfdec/swfdec_rtmp_connection.h>
+#include <swfdec/swfdec_rtmp_packet.h>
+
+G_BEGIN_DECLS
+
+
+#define SWFDEC_TYPE_RTMP_STREAM (swfdec_rtmp_stream_get_type ())
+#define SWFDEC_RTMP_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RTMP_STREAM, SwfdecRtmpStream))
+#define SWFDEC_IS_RTMP_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RTMP_STREAM))
+#define SWFDEC_RTMP_STREAM_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), SWFDEC_TYPE_RTMP_STREAM, SwfdecRtmpStreamInterface))
+
+typedef struct _SwfdecRtmpStreamInterface SwfdecRtmpStreamInterface;
+
+struct _SwfdecRtmpStreamInterface {
+ GTypeInterface parent;
+
+ /* mandatory vfunc */
+ void (* receive) (SwfdecRtmpStream * stream,
+ const SwfdecRtmpHeader * header,
+ SwfdecBuffer * buffer);
+ SwfdecRtmpPacket * (* sent) (SwfdecRtmpStream * stream,
+ const SwfdecRtmpPacket * packet);
+};
+
+GType swfdec_rtmp_stream_get_type (void) G_GNUC_CONST;
+
+void swfdec_rtmp_stream_receive (SwfdecRtmpStream * stream,
+ const SwfdecRtmpPacket *packet);
+SwfdecRtmpPacket * swfdec_rtmp_stream_sent (SwfdecRtmpStream * stream,
+ const SwfdecRtmpPacket *packet);
+
+
+G_END_DECLS
+
+#endif /* __SWFDEC_RTMP_STREAM_H__ */
commit 43ac22c4dcdb2ceb08bee5479670108cd693a9d6
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 9 18:51:34 2008 +0100
make sending work
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 41a66e8..02c33cc 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -26,10 +26,58 @@
#include "swfdec_as_frame_internal.h"
#include "swfdec_as_internal.h"
#include "swfdec_debug.h"
+#include "swfdec_sandbox.h"
+#include "swfdec_rtmp_rpc.h"
+#include "swfdec_rtmp_stream.h"
+
+#define SWFDEC_NET_STREAM_RPC_CHANNEL(stream) ((((stream)->stream - 1) * 5 % 65592) + 8)
+#define SWFDEC_NET_STREAM_VIDEO_CHANNEL(stream) ((((stream)->stream - 1) * 5 % 65592) + 5)
+#define SWFDEC_NET_STREAM_AUDIO_CHANNEL(stream) ((((stream)->stream - 1) * 5 % 65592) + 6)
+
+static void
+swfdec_net_stream_rtmp_stream_receive (SwfdecRtmpStream *rtmp_stream,
+ const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
+{
+ SwfdecNetStream *stream = SWFDEC_NET_STREAM (rtmp_stream);
+
+ switch ((guint) header->type) {
+ case SWFDEC_RTMP_PACKET_INVOKE:
+ swfdec_sandbox_use (stream->conn->sandbox);
+ if (swfdec_rtmp_rpc_receive (stream->rpc, buffer)) {
+ SwfdecRtmpPacket *packet = swfdec_rtmp_rpc_pop (stream->rpc, FALSE);
+ if (packet) {
+ packet->header.channel = SWFDEC_NET_STREAM_RPC_CHANNEL (stream);
+ packet->header.stream = stream->stream;
+ swfdec_rtmp_connection_send (stream->conn, packet);
+ }
+ }
+ swfdec_sandbox_unuse (stream->conn->sandbox);
+ break;
+ default:
+ SWFDEC_FIXME ("what to do with header type %u (channel %u, stream %u)?",
+ header->type, header->channel, header->stream);
+ break;
+ }
+}
+
+static SwfdecRtmpPacket *
+swfdec_net_stream_rtmp_stream_sent (SwfdecRtmpStream *stream,
+ const SwfdecRtmpPacket *packet)
+{
+ return NULL;
+}
+
+static void
+swfdec_net_stream_rtmp_stream_init (SwfdecRtmpStreamInterface *iface)
+{
+ iface->receive = swfdec_net_stream_rtmp_stream_receive;
+ iface->sent = swfdec_net_stream_rtmp_stream_sent;
+}
/*** NET STREAM ***/
-G_DEFINE_TYPE (SwfdecNetStream, swfdec_net_stream, SWFDEC_TYPE_AS_RELAY)
+G_DEFINE_TYPE_WITH_CODE (SwfdecNetStream, swfdec_net_stream, SWFDEC_TYPE_AS_RELAY,
+ G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_RTMP_STREAM, swfdec_net_stream_rtmp_stream_init))
static void
swfdec_net_stream_mark (SwfdecGcObject *object)
@@ -45,7 +93,12 @@ swfdec_net_stream_mark (SwfdecGcObject *object)
static void
swfdec_net_stream_dispose (GObject *object)
{
- //SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
+ SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
+
+ if (stream->rpc) {
+ swfdec_rtmp_rpc_free (stream->rpc);
+ stream->rpc = NULL;
+ }
G_OBJECT_CLASS (swfdec_net_stream_parent_class)->dispose (object);
}
@@ -62,7 +115,7 @@ swfdec_net_stream_class_init (SwfdecNetStreamClass *klass)
}
static void
-swfdec_net_stream_init (SwfdecNetStream *net_stream)
+swfdec_net_stream_init (SwfdecNetStream *stream)
{
}
@@ -147,6 +200,8 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream = g_object_new (SWFDEC_TYPE_NET_STREAM, "context", cx, NULL);
stream->conn = conn;
+ stream->rpc = swfdec_rtmp_rpc_new (conn, SWFDEC_AS_RELAY (stream));
+ swfdec_as_context_get_time (cx, &stream->rpc->last_send);
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
}
@@ -158,6 +213,7 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
SwfdecNetStream *stream;
SwfdecAsObject *o;
guint stream_id;
+ SwfdecRtmpPacket *packet;
SWFDEC_AS_CHECK (0, NULL, "oi", &o, &stream_id);
@@ -166,6 +222,15 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
stream = SWFDEC_NET_STREAM (o->relay);
stream->stream = stream_id;
+ swfdec_rtmp_connection_register_stream (stream->conn,
+ stream_id, SWFDEC_RTMP_STREAM (stream));
+
+ packet = swfdec_rtmp_rpc_pop (stream->rpc, FALSE);
+ if (packet) {
+ packet->header.channel = SWFDEC_NET_STREAM_RPC_CHANNEL (stream);
+ packet->header.stream = stream->stream;
+ swfdec_rtmp_connection_send (stream->conn, packet);
+ }
}
SWFDEC_AS_NATIVE (2101, 202, swfdec_net_stream_send_connection)
@@ -183,10 +248,15 @@ swfdec_net_stream_send_connection (SwfdecAsContext *cx, SwfdecAsObject *object,
return;
stream = SWFDEC_NET_STREAM (o->relay);
-#if 0
- swfdec_rtmp_rpc_channel_send (SWFDEC_RTMP_RPC_CHANNEL (
- stream->rpc_channel), name,
- ret_cb, MAX (3, argc) - 3, argv + 3);
-#endif
+ swfdec_rtmp_rpc_send (stream->rpc, name, ret_cb, MAX (3, argc) - 3, argv + 3);
+ /* FIXME: This should be done by some smart API */
+ if (stream->stream) {
+ SwfdecRtmpPacket *packet = swfdec_rtmp_rpc_pop (stream->rpc, FALSE);
+ if (packet) {
+ packet->header.channel = SWFDEC_NET_STREAM_RPC_CHANNEL (stream);
+ packet->header.stream = stream->stream;
+ swfdec_rtmp_connection_send (stream->conn, packet);
+ }
+ }
}
diff --git a/swfdec/swfdec_net_stream.h b/swfdec/swfdec_net_stream.h
index 7ece9fc..6aed2f8 100644
--- a/swfdec/swfdec_net_stream.h
+++ b/swfdec/swfdec_net_stream.h
@@ -39,6 +39,7 @@ struct _SwfdecNetStream {
SwfdecAsRelay relay;
SwfdecRtmpConnection * conn; /* the connection in use */
+ SwfdecRtmpRpc * rpc; /* rpc */
guint stream; /* id of this stream */
};
commit bb4a615585e037a19c0f5e8aa98349b8b21f4504
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 9 18:51:08 2008 +0100
rename registering funcs
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 208cc63..f11fdbf 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -291,7 +291,7 @@ swfdec_rtmp_connection_init (SwfdecRtmpConnection *conn)
conn->read_size = SWFDEC_RTMP_BLOCK_SIZE;
conn->write_size = SWFDEC_RTMP_BLOCK_SIZE;
- swfdec_rtmp_register_stream (conn, 0, SWFDEC_RTMP_STREAM (conn));
+ swfdec_rtmp_connection_register_stream (conn, 0, SWFDEC_RTMP_STREAM (conn));
}
void
@@ -373,7 +373,7 @@ swfdec_rtmp_connection_on_status (SwfdecRtmpConnection *conn, SwfdecAsValue valu
}
void
-swfdec_rtmp_register_stream (SwfdecRtmpConnection *conn,
+swfdec_rtmp_connection_register_stream (SwfdecRtmpConnection *conn,
guint id, SwfdecRtmpStream *stream)
{
g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
@@ -389,7 +389,7 @@ swfdec_rtmp_register_stream (SwfdecRtmpConnection *conn,
}
void
-swfdec_rtmp_unregister_stream (SwfdecRtmpConnection *conn, guint id)
+swfdec_rtmp_connection_unregister_stream (SwfdecRtmpConnection *conn, guint id)
{
g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
@@ -412,7 +412,7 @@ swfdec_rtmp_connection_send (SwfdecRtmpConnection *conn, SwfdecRtmpPacket *packe
packet->buffer->length = 0;
send = g_queue_is_empty (conn->packets);
g_queue_push_tail (conn->packets, packet);
- g_print ("pushed channel %u - %u packets now\n", packet->header.channel,
+ SWFDEC_LOG ("pushed channel %u - %u packets now", packet->header.channel,
g_queue_get_length (conn->packets));
if (send)
swfdec_rtmp_socket_send (conn->socket);
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index 13fbd7f..ed0f323 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -95,10 +95,10 @@ void swfdec_rtmp_connection_errorv (SwfdecRtmpConnection * conn,
void swfdec_rtmp_connection_on_status (SwfdecRtmpConnection * conn,
SwfdecAsValue value);
-void swfdec_rtmp_register_stream (SwfdecRtmpConnection * conn,
+void swfdec_rtmp_connection_register_stream (SwfdecRtmpConnection * conn,
guint id,
SwfdecRtmpStream * stream);
-void swfdec_rtmp_unregister_stream (SwfdecRtmpConnection * conn,
+void swfdec_rtmp_connection_unregister_stream(SwfdecRtmpConnection * conn,
guint id);
commit f991fe617b20f4272bf8ff7122f2a24d63f09d29
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 9 18:50:26 2008 +0100
decode NULL argument passed to all rpc calls, too
diff --git a/swfdec/swfdec_rtmp_rpc.c b/swfdec/swfdec_rtmp_rpc.c
index 4548181..e539bde 100644
--- a/swfdec/swfdec_rtmp_rpc.c
+++ b/swfdec/swfdec_rtmp_rpc.c
@@ -147,12 +147,19 @@ swfdec_rtmp_rpc_receive_call (SwfdecRtmpRpc *rpc, SwfdecAmfContext *cx,
SwfdecAsValue *args;
name = swfdec_as_value_to_string (context, val);
+
if (!swfdec_amf_decode (cx, bits, &val)) {
SWFDEC_ERROR ("could not decode reply id");
return FALSE;
}
id = swfdec_as_value_to_integer (context, val);
+ if (!swfdec_amf_decode (cx, bits, &val) ||
+ !SWFDEC_AS_VALUE_IS_NULL (val)) {
+ SWFDEC_ERROR ("could not decode null value");
+ return FALSE;
+ }
+
args = NULL;
for (i = 0; swfdec_bits_left (bits); i++) {
if ((i % 4) == 0)
commit 28729e8096d5f24f5923d0e16ac957354d852d6b
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 9 14:51:44 2008 +0100
make this stuff work without channels
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index b64264b..fc65e9d 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -131,18 +131,14 @@ libswfdec_source_files = \
swfdec_renderer.c \
swfdec_resource.c \
swfdec_ringbuffer.c \
- swfdec_rtmp_channel.c \
- swfdec_rtmp_control_channel.c \
swfdec_rtmp_connection.c \
swfdec_rtmp_handshake.c \
swfdec_rtmp_header.c \
swfdec_rtmp_packet.c \
- swfdec_rtmp_rpc_channel.c \
swfdec_rtmp_rpc.c \
swfdec_rtmp_socket.c \
swfdec_rtmp_socket_rtmp.c \
swfdec_rtmp_stream.c \
- swfdec_rtmp_video_channel.c \
swfdec_sandbox.c \
swfdec_script.c \
swfdec_selection.c \
@@ -333,18 +329,14 @@ noinst_HEADERS = \
swfdec_renderer_internal.h \
swfdec_resource.h \
swfdec_ringbuffer.h \
- swfdec_rtmp_channel.h \
- swfdec_rtmp_control_channel.h \
swfdec_rtmp_connection.h \
swfdec_rtmp_handshake.h \
swfdec_rtmp_header.h \
swfdec_rtmp_packet.h \
- swfdec_rtmp_rpc_channel.h \
swfdec_rtmp_rpc.h \
swfdec_rtmp_socket.h \
swfdec_rtmp_socket_rtmp.h \
swfdec_rtmp_stream.h \
- swfdec_rtmp_video_channel.h \
swfdec_sandbox.h \
swfdec_script_internal.h \
swfdec_shape.h \
diff --git a/swfdec/swfdec_net_connection.c b/swfdec/swfdec_net_connection.c
index 1d0479a..73a4ce7 100644
--- a/swfdec/swfdec_net_connection.c
+++ b/swfdec/swfdec_net_connection.c
@@ -35,7 +35,7 @@
#include "swfdec_debug.h"
#include "swfdec_internal.h"
#include "swfdec_player_internal.h"
-#include "swfdec_rtmp_rpc_channel.h"
+#include "swfdec_rtmp_rpc.h"
#include "swfdec_sandbox.h"
/*** AS CODE ***/
@@ -81,13 +81,25 @@ swfdec_net_connection_do_call (SwfdecAsContext *cx, SwfdecAsObject *object,
{
SwfdecRtmpConnection *conn;
SwfdecAsObject *ret_cb = NULL;
+ SwfdecRtmpPacket *packet;
SwfdecAsValue name;
SWFDEC_AS_CHECK (SWFDEC_TYPE_RTMP_CONNECTION, &conn, "v|O", &name, &ret_cb);
- swfdec_rtmp_rpc_channel_send (SWFDEC_RTMP_RPC_CHANNEL (
- swfdec_rtmp_connection_get_rpc_channel (conn)), name,
+ if (!swfdec_rtmp_connection_is_connected (conn)) {
+ SWFDEC_WARNING ("NetConnection.call does not work on closed connections.");
+ return;
+ }
+
+ swfdec_rtmp_rpc_send (conn->rpc, name,
ret_cb, MAX (2, argc) - 2, argv + 2);
+ /* FIXME: This should be done by some smart API */
+ packet = swfdec_rtmp_rpc_pop (conn->rpc, FALSE);
+ if (packet) {
+ packet->header.channel = 3;
+ packet->header.stream = 0;
+ swfdec_rtmp_connection_send (conn, packet);
+ }
}
SWFDEC_AS_NATIVE (2100, 3, swfdec_net_connection_do_addHeader)
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 163a9e8..41a66e8 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -26,8 +26,6 @@
#include "swfdec_as_frame_internal.h"
#include "swfdec_as_internal.h"
#include "swfdec_debug.h"
-#include "swfdec_rtmp_rpc_channel.h"
-#include "swfdec_rtmp_video_channel.h"
/*** NET STREAM ***/
@@ -47,14 +45,7 @@ swfdec_net_stream_mark (SwfdecGcObject *object)
static void
swfdec_net_stream_dispose (GObject *object)
{
- SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
-
- swfdec_rtmp_channel_unregister (stream->rpc_channel);
- g_object_unref (stream->rpc_channel);
- swfdec_rtmp_channel_unregister (stream->video_channel);
- g_object_unref (stream->video_channel);
- swfdec_rtmp_channel_unregister (stream->audio_channel);
- g_object_unref (stream->audio_channel);
+ //SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
G_OBJECT_CLASS (swfdec_net_stream_parent_class)->dispose (object);
}
@@ -157,12 +148,6 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream = g_object_new (SWFDEC_TYPE_NET_STREAM, "context", cx, NULL);
stream->conn = conn;
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
- stream->rpc_channel = swfdec_rtmp_rpc_channel_new (conn);
- swfdec_rtmp_rpc_channel_set_target (SWFDEC_RTMP_RPC_CHANNEL (stream->rpc_channel),
- swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (stream)));
- stream->video_channel = swfdec_rtmp_video_channel_new (conn);
- /* FIXME: new class for audio plz */
- stream->audio_channel = swfdec_rtmp_rpc_channel_new (conn);
}
SWFDEC_AS_NATIVE (2101, 201, swfdec_net_stream_onCreate)
@@ -172,7 +157,7 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
{
SwfdecNetStream *stream;
SwfdecAsObject *o;
- guint stream_id, channel_id;
+ guint stream_id;
SWFDEC_AS_CHECK (0, NULL, "oi", &o, &stream_id);
@@ -180,11 +165,7 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
return;
stream = SWFDEC_NET_STREAM (o->relay);
- stream->stream_id = stream_id;
- channel_id = 4 + ((stream_id - 1) * 5);
- swfdec_rtmp_channel_register (stream->rpc_channel, channel_id, stream_id);
- swfdec_rtmp_channel_register (stream->video_channel, channel_id + 1, stream_id);
- swfdec_rtmp_channel_register (stream->audio_channel, channel_id + 2, stream_id);
+ stream->stream = stream_id;
}
SWFDEC_AS_NATIVE (2101, 202, swfdec_net_stream_send_connection)
@@ -202,8 +183,10 @@ swfdec_net_stream_send_connection (SwfdecAsContext *cx, SwfdecAsObject *object,
return;
stream = SWFDEC_NET_STREAM (o->relay);
+#if 0
swfdec_rtmp_rpc_channel_send (SWFDEC_RTMP_RPC_CHANNEL (
stream->rpc_channel), name,
ret_cb, MAX (3, argc) - 3, argv + 3);
+#endif
}
diff --git a/swfdec/swfdec_net_stream.h b/swfdec/swfdec_net_stream.h
index 89297b8..7ece9fc 100644
--- a/swfdec/swfdec_net_stream.h
+++ b/swfdec/swfdec_net_stream.h
@@ -39,10 +39,7 @@ struct _SwfdecNetStream {
SwfdecAsRelay relay;
SwfdecRtmpConnection * conn; /* the connection in use */
- guint stream_id; /* id of this stream */
- SwfdecRtmpChannel * rpc_channel; /* channel used for RPC */
- SwfdecRtmpChannel * video_channel; /* channel used for video */
- SwfdecRtmpChannel * audio_channel; /* channel used for audio */
+ guint stream; /* id of this stream */
};
struct _SwfdecNetStreamClass {
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
deleted file mode 100644
index ea92761..0000000
--- a/swfdec/swfdec_rtmp_channel.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "swfdec_rtmp_channel.h"
-
-#include "swfdec_debug.h"
-#include "swfdec_rtmp_socket.h"
-
-/*** SwfdecRtmpChannel ***/
-
-enum {
- PROP_0,
- PROP_CONNECTION
-};
-
-G_DEFINE_ABSTRACT_TYPE (SwfdecRtmpChannel, swfdec_rtmp_channel, G_TYPE_OBJECT)
-
-static void
-swfdec_rtmp_channel_get_property (GObject *object, guint param_id, GValue *value,
- GParamSpec * pspec)
-{
- SwfdecRtmpChannel *channel = SWFDEC_RTMP_CHANNEL (object);
-
- switch (param_id) {
- case PROP_CONNECTION:
- g_value_set_object (value, channel->conn);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
-swfdec_rtmp_channel_set_property (GObject *object, guint param_id, const GValue *value,
- GParamSpec * pspec)
-{
- SwfdecRtmpChannel *channel = SWFDEC_RTMP_CHANNEL (object);
-
- switch (param_id) {
- case PROP_CONNECTION:
- channel->conn = g_value_get_object (value);
- g_assert (channel->conn != NULL);
- swfdec_rtmp_channel_get_time (channel, &channel->timestamp);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-static void
-swfdec_rtmp_channel_dispose (GObject *object)
-{
- SwfdecRtmpChannel *channel = SWFDEC_RTMP_CHANNEL (object);
-
- if (channel->recv_queue) {
- swfdec_buffer_queue_unref (channel->recv_queue);
- channel->recv_queue = NULL;
- }
- if (channel->send_queue) {
- swfdec_buffer_queue_unref (channel->send_queue);
- channel->send_queue = NULL;
- }
-
- G_OBJECT_CLASS (swfdec_rtmp_channel_parent_class)->dispose (object);
-}
-
-static void
-swfdec_rtmp_channel_class_init (SwfdecRtmpChannelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = swfdec_rtmp_channel_dispose;
- object_class->get_property = swfdec_rtmp_channel_get_property;
- object_class->set_property = swfdec_rtmp_channel_set_property;
-
- g_object_class_install_property (object_class, PROP_CONNECTION,
- g_param_spec_object ("connection", "connection", "RTMP connection this channel belongs to",
- SWFDEC_TYPE_RTMP_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-}
-
-static void
-swfdec_rtmp_channel_init (SwfdecRtmpChannel *channel)
-{
- swfdec_rtmp_header_invalidate (&channel->recv_cache);
- channel->recv_queue = swfdec_buffer_queue_new ();
- swfdec_rtmp_header_invalidate (&channel->send_cache);
- channel->send_queue = swfdec_buffer_queue_new ();
-}
-
-SwfdecBuffer *
-swfdec_rtmp_channel_next_buffer (SwfdecRtmpChannel *channel)
-{
- SwfdecRtmpChannelClass *klass;
- SwfdecRtmpPacket *packet;
- SwfdecRtmpHeader header;
- SwfdecBuffer *buffer;
- SwfdecBots *bots;
- guint i;
-
- g_return_val_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel), NULL);
- g_return_val_if_fail (swfdec_rtmp_channel_is_registered (channel), NULL);
-
- buffer = swfdec_buffer_queue_pull_buffer (channel->send_queue);
- if (buffer)
- return buffer;
-
- klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
- swfdec_rtmp_header_copy (&header, &channel->send_cache);
- packet = klass->send (channel);
- if (packet == NULL)
- return NULL;
-
- buffer = packet->buffer;
- bots = swfdec_bots_new ();
- header.channel = channel->channel_id;
- header.type = packet->header.type;
- header.timestamp = packet->header.timestamp;
- header.size = buffer->length;
- header.stream = channel->stream_id;
-
- swfdec_rtmp_header_write (&header, bots,
- swfdec_rtmp_header_diff (&header, &channel->send_cache));
- swfdec_rtmp_header_copy (&channel->send_cache, &header);
-
- for (i = 0; i < buffer->length; i += SWFDEC_RTMP_BLOCK_SIZE) {
- if (i != 0) {
- /* write a continuation header */
- bots = swfdec_bots_new ();
- swfdec_rtmp_header_write (&header, bots, SWFDEC_RTMP_HEADER_1_BYTE);
- }
- swfdec_bots_put_data (bots, buffer->data + i, MIN (SWFDEC_RTMP_BLOCK_SIZE, buffer->length - i));
- swfdec_buffer_queue_push (channel->send_queue, swfdec_bots_close (bots));
- }
- swfdec_rtmp_packet_free (packet);
-
- return swfdec_buffer_queue_pull_buffer (channel->send_queue);
-}
-
-static int
-swfdec_rtmp_channel_compare (gconstpointer a, gconstpointer b)
-{
- SwfdecRtmpChannel *ca = (SwfdecRtmpChannel *) a;
- SwfdecRtmpChannel *cb = (SwfdecRtmpChannel *) b;
-
- return cb->channel_id - ca->channel_id;
-}
-
-void
-swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel,
- guint channel_id, guint stream_id)
-{
- SwfdecRtmpConnection *conn;
-
- g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
- g_return_if_fail (!swfdec_rtmp_channel_is_registered (channel));
- g_return_if_fail (channel_id > 1);
-
- if (channel_id >= 65536 + 64) {
- SWFDEC_FIXME ("figure out how huge ids (like %u) are handled. Channel registration failed", channel_id);
- return;
- }
- SWFDEC_DEBUG ("registering %s as channel %u for stream %u", G_OBJECT_TYPE_NAME (channel),
- channel_id, stream_id);
-
- conn = channel->conn;
- conn->channels = g_list_insert_sorted (conn->channels, channel,
- swfdec_rtmp_channel_compare);
- channel->channel_id = channel_id;
- channel->stream_id = stream_id;
- g_object_ref (channel);
-
- swfdec_rtmp_socket_send (channel->conn->socket);
-}
-
-void
-swfdec_rtmp_channel_unregister (SwfdecRtmpChannel *channel)
-{
- g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
-
- if (!swfdec_rtmp_channel_is_registered (channel))
- return;
-
- if (channel->conn->last_send->data == channel) {
- channel->conn->last_send = channel->conn->last_send->next ?
- channel->conn->last_send->next : channel->conn->last_send->prev;
- }
- channel->conn->channels = g_list_remove (channel->conn->channels, channel);
- channel->channel_id = 0;
- channel->stream_id = 0;
- g_object_unref (channel);
-}
-
diff --git a/swfdec/swfdec_rtmp_channel.h b/swfdec/swfdec_rtmp_channel.h
deleted file mode 100644
index 4fa985a..0000000
--- a/swfdec/swfdec_rtmp_channel.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _SWFDEC_RTMP_CHANNEL_H_
-#define _SWFDEC_RTMP_CHANNEL_H_
-
-#include <swfdec/swfdec_rtmp_connection.h>
-#include <swfdec/swfdec_rtmp_header.h>
-#include <swfdec/swfdec_rtmp_packet.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _SwfdecRtmpChannelClass SwfdecRtmpChannelClass;
-
-#define SWFDEC_TYPE_RTMP_CHANNEL (swfdec_rtmp_channel_get_type())
-#define SWFDEC_IS_RTMP_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RTMP_CHANNEL))
-#define SWFDEC_IS_RTMP_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_RTMP_CHANNEL))
-#define SWFDEC_RTMP_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RTMP_CHANNEL, SwfdecRtmpChannel))
-#define SWFDEC_RTMP_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_RTMP_CHANNEL, SwfdecRtmpChannelClass))
-#define SWFDEC_RTMP_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_RTMP_CHANNEL, SwfdecRtmpChannelClass))
-
-struct _SwfdecRtmpChannel {
- GObject object;
-
- SwfdecRtmpConnection * conn; /* Connection this channel belongs to */
- guint channel_id; /* channel id inside connection or 0 if no connection */
- guint stream_id; /* stream id inside connection */
-
- GTimeVal timestamp; /* timestamp for various uses - set when constructing */
- SwfdecRtmpHeader recv_cache; /* cached header info for receiving data */
- SwfdecBufferQueue * recv_queue; /* Queue of semi-assembled packages when receiving */
- SwfdecRtmpHeader send_cache; /* cached header info for sending data */
- SwfdecBufferQueue * send_queue; /* Queue of outgoing waiting for delivery */
-};
-
-struct _SwfdecRtmpChannelClass {
- GObjectClass object_class;
-
- void (* mark) (SwfdecRtmpChannel * channel);
- void (* receive) (SwfdecRtmpChannel * channel,
- const SwfdecRtmpHeader *header,
- SwfdecBuffer * buffer);
- SwfdecRtmpPacket * (* send) (SwfdecRtmpChannel * channel);
-};
-
-GType swfdec_rtmp_channel_get_type (void);
-
-SwfdecBuffer * swfdec_rtmp_channel_next_buffer (SwfdecRtmpChannel * channel);
-
-#define swfdec_rtmp_channel_get_time(channel, tv) (swfdec_as_context_get_time (swfdec_gc_object_get_context ((channel)->conn), tv))
-#define swfdec_rtmp_channel_is_registered(channel) ((channel)->channel_id > 0)
-#define swfdec_rtmp_channel_send(channel) G_STMT_START{\
- if (swfdec_rtmp_channel_is_registered(channel)) \
- swfdec_rtmp_socket_send (channel->conn->socket); \
-}G_STMT_END
-void swfdec_rtmp_channel_register (SwfdecRtmpChannel * channel,
- guint channel_id,
- guint stream_id);
-void swfdec_rtmp_channel_unregister (SwfdecRtmpChannel * channel);
-
-
-
-G_END_DECLS
-#endif
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index fcf3418..208cc63 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -28,34 +28,180 @@
#include "swfdec_as_strings.h"
#include "swfdec_bots.h"
#include "swfdec_debug.h"
-#include "swfdec_rtmp_control_channel.h"
+#include "swfdec_sandbox.h"
#include "swfdec_rtmp_handshake.h"
-#include "swfdec_rtmp_rpc_channel.h"
+#include "swfdec_rtmp_rpc.h"
#include "swfdec_rtmp_socket.h"
#include "swfdec_rtmp_stream.h"
+#include "swfdec_utils.h"
/*** SwfdecRtmpStream ***/
static void
+swfdec_rtmp_connection_push_control (SwfdecRtmpConnection *conn,
+ SwfdecRtmpPacket *packet)
+{
+ g_return_if_fail (packet->header.channel == 2);
+
+ if (g_queue_is_empty (conn->control_packets)) {
+ g_queue_push_tail (conn->control_packets, NULL);
+ swfdec_rtmp_connection_send (conn, packet);
+ } else {
+ g_queue_push_tail (conn->control_packets, packet);
+ }
+}
+
+static void
+swfdec_rtmp_connection_handle_chunk_size (SwfdecRtmpConnection *conn, SwfdecBuffer *buffer)
+{
+ SwfdecBits bits;
+ guint new_size;
+
+ swfdec_bits_init (&bits, buffer);
+ new_size = swfdec_bits_get_bu32 (&bits);
+ SWFDEC_INFO ("altering read chunk size %u => %u", conn->read_size, new_size);
+ conn->read_size = new_size;
+ if (swfdec_bits_left (&bits)) {
+ SWFDEC_FIXME ("%u bytes left after chunk size", swfdec_bits_left (&bits) / 8);
+ }
+}
+
+static void
+swfdec_rtmp_connection_handle_ping (SwfdecRtmpConnection *conn, SwfdecBuffer *buffer)
+{
+ SwfdecBits bits;
+ guint type, target;
+
+ swfdec_bits_init (&bits, buffer);
+ type = swfdec_bits_get_bu16 (&bits);
+ target = swfdec_bits_get_bu32 (&bits);
+ SWFDEC_FIXME ("handle ping type %u for target %u", type, target);
+}
+
+static void
+swfdec_rtmp_connection_handle_server_bandwidth (SwfdecRtmpConnection *conn,
+ const SwfdecRtmpHeader *org_header, SwfdecBuffer *buffer)
+{
+ SwfdecBits bits;
+ SwfdecBots *bots;
+ guint new_bandwidth;
+ SwfdecRtmpPacket *packet;
+ GTimeVal tv;
+ long diff;
+
+ swfdec_bits_init (&bits, buffer);
+ new_bandwidth = swfdec_bits_get_bu32 (&bits);
+ SWFDEC_INFO ("new server bandwidth set: %u => %u",
+ conn->server_bandwidth, new_bandwidth);
+ conn->server_bandwidth = new_bandwidth;
+
+ /* I guess this is for telling the server to throttle if we know our bandwidth is smaller */
+ bots = swfdec_bots_new ();
+ swfdec_bots_put_bu32 (bots, new_bandwidth);
+ buffer = swfdec_bots_close (bots);
+ /* send diff between the timestamp that the server sent and our current time.
+ * FIXME: Is that correct? */
+ swfdec_as_context_get_time (swfdec_gc_object_get_context (conn), &tv);
+ diff = swfdec_time_val_diff (&conn->connect_time, &tv);
+ packet = swfdec_rtmp_packet_new (2, 0, SWFDEC_RTMP_PACKET_SERVER_BANDWIDTH,
+ org_header->timestamp - diff, buffer);
+ swfdec_buffer_unref (buffer);
+
+ swfdec_rtmp_connection_push_control (conn, packet);
+}
+
+static void
+swfdec_rtmp_connection_handle_client_bandwidth (SwfdecRtmpConnection *conn, SwfdecBuffer *buffer)
+{
+ SwfdecBits bits;
+ guint magic;
+
+ swfdec_bits_init (&bits, buffer);
+ conn->client_bandwidth = swfdec_bits_get_bu32 (&bits);
+ magic = swfdec_bits_get_u8 (&bits);
+ SWFDEC_INFO ("client bandwidth is %u, magic value set to %u",
+ conn->client_bandwidth, magic);
+}
+
+static void
swfdec_rtmp_connection_rtmp_stream_receive (SwfdecRtmpStream *stream,
const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
{
SwfdecRtmpConnection *conn = SWFDEC_RTMP_CONNECTION (stream);
- SwfdecRtmpChannel *channel = swfdec_rtmp_connection_get_channel (conn, header->channel);
- SwfdecRtmpChannelClass *klass;
-
- if (channel == NULL) {
- SWFDEC_FIXME ("woot, no channel %u", header->channel);
- return;
+
+ switch ((guint) header->type) {
+ case SWFDEC_RTMP_PACKET_SIZE:
+ swfdec_rtmp_connection_handle_chunk_size (conn, buffer);
+ break;
+ case SWFDEC_RTMP_PACKET_PING:
+ swfdec_rtmp_connection_handle_ping (conn, buffer);
+ break;
+ case SWFDEC_RTMP_PACKET_SERVER_BANDWIDTH:
+ swfdec_rtmp_connection_handle_server_bandwidth (conn, header, buffer);
+ break;
+ case SWFDEC_RTMP_PACKET_CLIENT_BANDWIDTH:
+ swfdec_rtmp_connection_handle_client_bandwidth (conn, buffer);
+ break;
+ case SWFDEC_RTMP_PACKET_INVOKE:
+ swfdec_sandbox_use (conn->sandbox);
+ if (swfdec_rtmp_rpc_receive (conn->rpc, buffer)) {
+ SwfdecRtmpPacket *packet = swfdec_rtmp_rpc_pop (conn->rpc, FALSE);
+ if (packet) {
+ packet->header.channel = 3;
+ packet->header.stream = 0;
+ swfdec_rtmp_connection_send (conn, packet);
+ }
+ }
+ swfdec_sandbox_unuse (conn->sandbox);
+ break;
+ default:
+ SWFDEC_FIXME ("what to do with header type %u (channel %u)?", header->type,
+ header->channel);
+ break;
+ }
+}
+
+static SwfdecRtmpPacket *
+swfdec_rtmp_connection_rtmp_stream_sent (SwfdecRtmpStream *stream,
+ const SwfdecRtmpPacket *packet)
+{
+ SwfdecRtmpConnection *conn = SWFDEC_RTMP_CONNECTION (stream);
+ SwfdecRtmpPacket *result = NULL;
+
+ switch (packet->header.channel) {
+ case 2:
+ {
+ GList *list;
+ if (g_queue_pop_head (conn->control_packets) != NULL) {
+ g_assert_not_reached ();
+ }
+ list = g_queue_peek_head_link (conn->control_packets);
+ if (list) {
+ result = list->data;
+ list->data = NULL;
+ }
+ }
+ break;
+ case 3:
+ result = swfdec_rtmp_rpc_pop (conn->rpc, TRUE);
+ if (result) {
+ result->header.channel = 3;
+ result->header.stream = 0;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
}
- klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
- klass->receive (channel, header, buffer);
+
+ return result;
}
static void
swfdec_rtmp_connection_rtmp_stream_init (SwfdecRtmpStreamInterface *iface)
{
iface->receive = swfdec_rtmp_connection_rtmp_stream_receive;
+ iface->sent = swfdec_rtmp_connection_rtmp_stream_sent;
}
/*** SwfdecRtmpConnection ***/
@@ -67,18 +213,22 @@ static void
swfdec_rtmp_connection_mark (SwfdecGcObject *object)
{
SwfdecRtmpConnection *conn = SWFDEC_RTMP_CONNECTION (object);
- GList *walk;
- for (walk = conn->channels; walk; walk = walk->next) {
- SwfdecRtmpChannel *channel = walk->data;
- SwfdecRtmpChannelClass *klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
- if (klass->mark)
- klass->mark (channel);
- }
+ swfdec_rtmp_rpc_mark (conn->rpc);
SWFDEC_GC_OBJECT_CLASS (swfdec_rtmp_connection_parent_class)->mark (object);
}
+/* This function is necessary because we use packet->buffer->length as our write counter */
+static void
+swfdec_rtmp_connection_packets_free (gpointer packetp)
+{
+ SwfdecRtmpPacket *packet = packetp;
+
+ packet->buffer->length = packet->header.size;
+ swfdec_rtmp_packet_free (packet);
+}
+
static void
swfdec_rtmp_connection_dispose (GObject *object)
{
@@ -98,6 +248,20 @@ swfdec_rtmp_connection_dispose (GObject *object)
g_hash_table_destroy (conn->streams);
conn->streams = NULL;
}
+ if (conn->packets) {
+ g_queue_foreach (conn->packets, (GFunc) swfdec_rtmp_connection_packets_free, NULL);
+ g_queue_free (conn->packets);
+ conn->packets = NULL;
+ }
+ if (conn->control_packets) {
+ g_queue_foreach (conn->control_packets, (GFunc) swfdec_rtmp_packet_free, NULL);
+ g_queue_free (conn->control_packets);
+ conn->control_packets = NULL;
+ }
+ if (conn->rpc) {
+ swfdec_rtmp_rpc_free (conn->rpc);
+ conn->rpc = NULL;
+ }
G_OBJECT_CLASS (swfdec_rtmp_connection_parent_class)->dispose (object);
}
@@ -119,6 +283,10 @@ swfdec_rtmp_connection_init (SwfdecRtmpConnection *conn)
conn->incoming = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) swfdec_rtmp_packet_free);
conn->streams = g_hash_table_new (g_direct_hash, g_direct_equal);
+ conn->packets = g_queue_new ();
+
+ conn->control_packets = g_queue_new ();
+ conn->rpc = swfdec_rtmp_rpc_new (conn, SWFDEC_AS_RELAY (conn));
conn->read_size = SWFDEC_RTMP_BLOCK_SIZE;
conn->write_size = SWFDEC_RTMP_BLOCK_SIZE;
@@ -129,8 +297,6 @@ swfdec_rtmp_connection_init (SwfdecRtmpConnection *conn)
void
swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url)
{
- SwfdecRtmpChannel *channel;
-
g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
swfdec_rtmp_connection_close (conn);
@@ -145,16 +311,9 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
if (conn->error)
return;
+ swfdec_as_context_get_time (swfdec_gc_object_get_context (conn), &conn->connect_time);
+ conn->rpc->last_send = conn->connect_time;
conn->handshake = swfdec_rtmp_handshake_new (conn);
-
- channel = swfdec_rtmp_control_channel_new (conn);
- swfdec_rtmp_channel_register (channel, 2, 0);
- g_object_unref (channel);
- channel = swfdec_rtmp_rpc_channel_new (conn);
- swfdec_rtmp_channel_register (channel, 3, 0);
- g_object_unref (channel);
- conn->last_send = conn->channels;
-
swfdec_rtmp_socket_send (conn->socket);
}
@@ -163,17 +322,13 @@ swfdec_rtmp_connection_close (SwfdecRtmpConnection *conn)
{
g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
- while (conn->channels)
- swfdec_rtmp_channel_unregister (conn->channels->data);
+ if (!swfdec_rtmp_connection_is_connected (conn))
+ return;
- if (conn->socket) {
- g_object_unref (conn->socket);
- conn->socket = NULL;
- }
- if (conn->url) {
- swfdec_url_free (conn->url);
- conn->url = NULL;
- }
+ g_object_unref (conn->socket);
+ conn->socket = NULL;
+ swfdec_url_free (conn->url);
+ conn->url = NULL;
}
void
@@ -217,27 +372,6 @@ swfdec_rtmp_connection_on_status (SwfdecRtmpConnection *conn, SwfdecAsValue valu
swfdec_as_relay_call (SWFDEC_AS_RELAY (conn), SWFDEC_AS_STR_onStatus, 1, &value, NULL);
}
-SwfdecRtmpChannel *
-swfdec_rtmp_connection_get_channel (SwfdecRtmpConnection *conn, guint id)
-{
- SwfdecRtmpChannel *channel;
- GList *walk;
-
- g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
- g_return_val_if_fail (conn->channels != NULL, NULL);
-
- for (walk = conn->channels; walk; walk = walk->next) {
- channel = walk->data;
- if (channel->channel_id < id)
- continue;
- if (channel->channel_id == id)
- return channel;
- return NULL;
- }
-
- return NULL;
-}
-
void
swfdec_rtmp_register_stream (SwfdecRtmpConnection *conn,
guint id, SwfdecRtmpStream *stream)
@@ -263,3 +397,23 @@ swfdec_rtmp_unregister_stream (SwfdecRtmpConnection *conn, guint id)
g_assert_not_reached ();
}
}
+
+void
+swfdec_rtmp_connection_send (SwfdecRtmpConnection *conn, SwfdecRtmpPacket *packet)
+{
+ gboolean send;
+
+ g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
+ g_return_if_fail (packet != NULL);
+ /* FIXME: I'd like a g_return_if_fail (packet->channel is not already sent),
+ * but that requires a g_queue_find_custom () and that's slow */
+
+ g_assert (packet->header.size == packet->buffer->length);
+ packet->buffer->length = 0;
+ send = g_queue_is_empty (conn->packets);
+ g_queue_push_tail (conn->packets, packet);
+ g_print ("pushed channel %u - %u packets now\n", packet->header.channel,
+ g_queue_get_length (conn->packets));
+ if (send)
+ swfdec_rtmp_socket_send (conn->socket);
+}
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index 2a900df..13fbd7f 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -23,6 +23,7 @@
#include <swfdec/swfdec.h>
#include <swfdec/swfdec_as_relay.h>
#include <swfdec/swfdec_rtmp_header.h>
+#include <swfdec/swfdec_rtmp_packet.h>
#include <swfdec/swfdec_types.h>
G_BEGIN_DECLS
@@ -32,8 +33,8 @@ G_BEGIN_DECLS
#define SWFDEC_RTMP_BLOCK_SIZE 128
/* forward declarations */
-typedef struct _SwfdecRtmpChannel SwfdecRtmpChannel;
typedef struct _SwfdecRtmpHandshake SwfdecRtmpHandshake;
+typedef struct _SwfdecRtmpRpc SwfdecRtmpRpc;
typedef struct _SwfdecRtmpSocket SwfdecRtmpSocket;
typedef struct _SwfdecRtmpStream SwfdecRtmpStream;
@@ -53,15 +54,20 @@ struct _SwfdecRtmpConnection {
SwfdecURL * url; /* URL in use by this connection */
SwfdecSandbox * sandbox; /* sandbox we execute functions in or NULL */
SwfdecRtmpSocket * socket; /* socket we're using for read/write */
- GList * channels; /* list of channels in use by this connection (ordered by channel) */
- GList * last_send; /* list entry of last channel sent to */
SwfdecRtmpHandshake * handshake; /* structure used for doing initial handshake or NULL */
char * error; /* NULL or debug string for error message */
GHashTable * incoming; /* channel id => incoming packets */
GHashTable * streams; /* stream id => stream */
+ GQueue * packets; /* queue of packets in send order */
+ GTimeVal connect_time; /* time at which this connectioon was opened */
+
+ GQueue * control_packets;/* packets waiting to be sent on queue 2 */
+ SwfdecRtmpRpc * rpc; /* queue for rpc */
guint read_size; /* size of a block of data when reading */
guint write_size; /* size of a block of data when writing */
+ guint server_bandwidth; /* ??? */
+ guint client_bandwidth; /* ??? */
};
struct _SwfdecRtmpConnectionClass {
@@ -70,15 +76,16 @@ struct _SwfdecRtmpConnectionClass {
GType swfdec_rtmp_connection_get_type (void);
+#define swfdec_rtmp_connection_is_connected(conn) ((conn)->socket != NULL)
void swfdec_rtmp_connection_connect (SwfdecRtmpConnection * conn,
const SwfdecURL * url);
void swfdec_rtmp_connection_close (SwfdecRtmpConnection * conn);
void swfdec_rtmp_connection_receive (SwfdecRtmpConnection * conn,
SwfdecBufferQueue * queue);
-void swfdec_rtmp_connection_send (SwfdecRtmpConnection * conn);
-SwfdecRtmpChannel * swfdec_rtmp_connection_get_channel (SwfdecRtmpConnection * conn,
- guint id);
+void swfdec_rtmp_connection_send (SwfdecRtmpConnection * conn,
+ SwfdecRtmpPacket * packet);
+
void swfdec_rtmp_connection_error (SwfdecRtmpConnection * conn,
const char * error,
...) G_GNUC_PRINTF (2, 3);
@@ -94,9 +101,6 @@ void swfdec_rtmp_register_stream (SwfdecRtmpConnection * conn,
void swfdec_rtmp_unregister_stream (SwfdecRtmpConnection * conn,
guint id);
-#define swfdec_rtmp_connection_get_command_channel(conn) (swfdec_rtmp_connection_get_channel (conn, 2))
-#define swfdec_rtmp_connection_get_rpc_channel(conn) (swfdec_rtmp_connection_get_channel (conn, 3))
-
G_END_DECLS
#endif
diff --git a/swfdec/swfdec_rtmp_control_channel.c b/swfdec/swfdec_rtmp_control_channel.c
deleted file mode 100644
index 013862a..0000000
--- a/swfdec/swfdec_rtmp_control_channel.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "swfdec_rtmp_control_channel.h"
-
-#include "swfdec_debug.h"
-#include "swfdec_rtmp_socket.h"
-#include "swfdec_utils.h"
-
-/*** SwfdecRtmpControlChannel ***/
-
-G_DEFINE_TYPE (SwfdecRtmpControlChannel, swfdec_rtmp_control_channel, SWFDEC_TYPE_RTMP_CHANNEL)
-
-static void
-swfdec_rtmp_control_channel_push (SwfdecRtmpControlChannel *control,
- SwfdecRtmpPacket *packet)
-{
- gboolean empty = g_queue_is_empty (control->send_packets);
-
- g_queue_push_tail (control->send_packets, packet);
-
- if (empty)
- swfdec_rtmp_channel_send (SWFDEC_RTMP_CHANNEL (control));
-}
-
-static void
-swfdec_rtmp_control_channel_handle_chunk_size (SwfdecRtmpChannel *channel, SwfdecBuffer *buffer)
-{
- SwfdecBits bits;
-
- swfdec_bits_init (&bits, buffer);
- channel->conn->read_size = swfdec_bits_get_bu32 (&bits);
- SWFDEC_INFO ("setting read chunk size to %u", channel->conn->read_size);
- if (swfdec_bits_left (&bits)) {
- SWFDEC_FIXME ("%u bytes left after chunk size", swfdec_bits_left (&bits) / 8);
- }
-}
-
-static void
-swfdec_rtmp_control_channel_handle_ping (SwfdecRtmpChannel *channel, SwfdecBuffer *buffer)
-{
- SwfdecBits bits;
- guint type, target;
-
- swfdec_bits_init (&bits, buffer);
- type = swfdec_bits_get_bu16 (&bits);
- target = swfdec_bits_get_bu32 (&bits);
- SWFDEC_FIXME ("handle ping type %u for target %u", type, target);
-}
-
-static void
-swfdec_rtmp_control_channel_handle_server_bandwidth (SwfdecRtmpChannel *channel,
- const SwfdecRtmpHeader *org_header, SwfdecBuffer *buffer)
-{
- SwfdecRtmpControlChannel *control = SWFDEC_RTMP_CONTROL_CHANNEL (channel);
- SwfdecBits bits;
- SwfdecBots *bots;
- guint new_bandwidth;
- SwfdecRtmpPacket *packet;
- GTimeVal tv;
- long diff;
-
- swfdec_bits_init (&bits, buffer);
- new_bandwidth = swfdec_bits_get_bu32 (&bits);
- SWFDEC_INFO ("new server bandwidth set: %u => %u",
- control->server_bandwidth, new_bandwidth);
- control->server_bandwidth = new_bandwidth;
-
- /* I guess this is for telling the server to throttle if we know our bandwidth is smaller */
- bots = swfdec_bots_new ();
- swfdec_bots_put_bu32 (bots, new_bandwidth);
- buffer = swfdec_bots_close (bots);
- /* send diff between the timestamp that the server sent and our current time.
- * FIXME: Is that correct? */
- swfdec_rtmp_channel_get_time (channel, &tv);
- diff = swfdec_time_val_diff (&channel->timestamp, &tv);
- packet = swfdec_rtmp_packet_new (SWFDEC_RTMP_PACKET_SERVER_BANDWIDTH,
- org_header->timestamp - diff, buffer);
- swfdec_buffer_unref (buffer);
-
- swfdec_rtmp_control_channel_push (control, packet);
-}
-
-static void
-swfdec_rtmp_control_channel_handle_client_bandwidth (SwfdecRtmpChannel *channel, SwfdecBuffer *buffer)
-{
- SwfdecRtmpControlChannel *control = SWFDEC_RTMP_CONTROL_CHANNEL (channel);
- SwfdecBits bits;
- guint magic;
-
- swfdec_bits_init (&bits, buffer);
- control->client_bandwidth = swfdec_bits_get_bu32 (&bits);
- magic = swfdec_bits_get_u8 (&bits);
- SWFDEC_INFO ("client bandwidth is %u, magic value set to %u",
- control->client_bandwidth, magic);
-}
-
-static void
-swfdec_rtmp_control_channel_receive (SwfdecRtmpChannel *channel,
- const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
-{
- switch ((guint) header->type) {
- case SWFDEC_RTMP_PACKET_SIZE:
- swfdec_rtmp_control_channel_handle_chunk_size (channel, buffer);
- break;
- case SWFDEC_RTMP_PACKET_PING:
- swfdec_rtmp_control_channel_handle_ping (channel, buffer);
- break;
- case SWFDEC_RTMP_PACKET_SERVER_BANDWIDTH:
- swfdec_rtmp_control_channel_handle_server_bandwidth (channel, header, buffer);
- break;
- case SWFDEC_RTMP_PACKET_CLIENT_BANDWIDTH:
- swfdec_rtmp_control_channel_handle_client_bandwidth (channel, buffer);
- break;
- default:
- SWFDEC_FIXME ("what to do with header type %u?", header->type);
- break;
- }
-}
-
-static SwfdecRtmpPacket *
-swfdec_rtmp_control_channel_send (SwfdecRtmpChannel *channel)
-{
- SwfdecRtmpControlChannel *control = SWFDEC_RTMP_CONTROL_CHANNEL (channel);
-
- return g_queue_pop_head (control->send_packets);
-}
-
-static void
-swfdec_rtmp_control_channel_dispose (GObject *object)
-{
- SwfdecRtmpControlChannel *control = SWFDEC_RTMP_CONTROL_CHANNEL (object);
-
- if (control->send_packets) {
- g_queue_foreach (control->send_packets, (GFunc) swfdec_rtmp_packet_free, NULL);
- g_queue_free (control->send_packets);
- control->send_packets = NULL;
- }
-
- G_OBJECT_CLASS (swfdec_rtmp_control_channel_parent_class)->dispose (object);
-}
-
-static void
-swfdec_rtmp_control_channel_class_init (SwfdecRtmpControlChannelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- SwfdecRtmpChannelClass *channel_class = SWFDEC_RTMP_CHANNEL_CLASS (klass);
-
- object_class->dispose = swfdec_rtmp_control_channel_dispose;
-
- channel_class->receive = swfdec_rtmp_control_channel_receive;
- channel_class->send = swfdec_rtmp_control_channel_send;
-}
-
-static void
-swfdec_rtmp_control_channel_init (SwfdecRtmpControlChannel *control)
-{
- control->send_packets = g_queue_new ();
-}
-
-SwfdecRtmpChannel *
-swfdec_rtmp_control_channel_new (SwfdecRtmpConnection *conn)
-{
- g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
-
- return g_object_new (SWFDEC_TYPE_RTMP_CONTROL_CHANNEL, "connection", conn, NULL);
-}
diff --git a/swfdec/swfdec_rtmp_control_channel.h b/swfdec/swfdec_rtmp_control_channel.h
deleted file mode 100644
index 5a56bc6..0000000
--- a/swfdec/swfdec_rtmp_control_channel.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _SWFDEC_RTMP_CONTROL_CHANNEL_H_
-#define _SWFDEC_RTMP_CONTROL_CHANNEL_H_
-
-#include <swfdec/swfdec_rtmp_channel.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _SwfdecRtmpControlChannel SwfdecRtmpControlChannel;
-typedef struct _SwfdecRtmpControlChannelClass SwfdecRtmpControlChannelClass;
-
-#define SWFDEC_TYPE_RTMP_CONTROL_CHANNEL (swfdec_rtmp_control_channel_get_type())
-#define SWFDEC_IS_RTMP_CONTROL_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RTMP_CONTROL_CHANNEL))
-#define SWFDEC_IS_RTMP_CONTROL_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_RTMP_CONTROL_CHANNEL))
-#define SWFDEC_RTMP_CONTROL_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RTMP_CONTROL_CHANNEL, SwfdecRtmpControlChannel))
-#define SWFDEC_RTMP_CONTROL_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_RTMP_CONTROL_CHANNEL, SwfdecRtmpControlChannelClass))
-#define SWFDEC_RTMP_CONTROL_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_RTMP_CONTROL_CHANNEL, SwfdecRtmpControlChannelClass))
-
-struct _SwfdecRtmpControlChannel {
- SwfdecRtmpChannel channel;
-
- GQueue * send_packets; /* packets that still need to be sent */
- guint server_bandwidth;
- guint client_bandwidth;
-};
-
-struct _SwfdecRtmpControlChannelClass {
- SwfdecRtmpChannelClass channel_class;
-};
-
-GType swfdec_rtmp_control_channel_get_type (void);
-
-SwfdecRtmpChannel * swfdec_rtmp_control_channel_new (SwfdecRtmpConnection * conn);
-
-
-G_END_DECLS
-#endif
diff --git a/swfdec/swfdec_rtmp_packet.c b/swfdec/swfdec_rtmp_packet.c
index ae3d133..be2c2a8 100644
--- a/swfdec/swfdec_rtmp_packet.c
+++ b/swfdec/swfdec_rtmp_packet.c
@@ -30,16 +30,19 @@ swfdec_rtmp_packet_new_empty (void)
}
SwfdecRtmpPacket *
-swfdec_rtmp_packet_new (SwfdecRtmpPacketType type, guint timestamp,
- SwfdecBuffer *buffer)
+swfdec_rtmp_packet_new (guint channel, guint stream, SwfdecRtmpPacketType type,
+ guint timestamp, SwfdecBuffer *buffer)
{
SwfdecRtmpPacket *packet;
g_return_val_if_fail (buffer != NULL, NULL);
packet = swfdec_rtmp_packet_new_empty ();
+ packet->header.channel = channel;
+ packet->header.stream = stream;
packet->header.type = type;
packet->header.timestamp = timestamp;
+ packet->header.size = buffer->length;
packet->buffer = swfdec_buffer_ref (buffer);
return packet;
diff --git a/swfdec/swfdec_rtmp_packet.h b/swfdec/swfdec_rtmp_packet.h
index 96482f0..eee13cc 100644
--- a/swfdec/swfdec_rtmp_packet.h
+++ b/swfdec/swfdec_rtmp_packet.h
@@ -34,7 +34,9 @@ struct _SwfdecRtmpPacket {
};
SwfdecRtmpPacket * swfdec_rtmp_packet_new_empty (void);
-SwfdecRtmpPacket * swfdec_rtmp_packet_new (SwfdecRtmpPacketType type,
+SwfdecRtmpPacket * swfdec_rtmp_packet_new (guint channel,
+ guint stream,
+ SwfdecRtmpPacketType type,
guint timestamp,
SwfdecBuffer * buffer);
void swfdec_rtmp_packet_free (SwfdecRtmpPacket * packet);
diff --git a/swfdec/swfdec_rtmp_rpc.c b/swfdec/swfdec_rtmp_rpc.c
index 984552a..4548181 100644
--- a/swfdec/swfdec_rtmp_rpc.c
+++ b/swfdec/swfdec_rtmp_rpc.c
@@ -77,7 +77,7 @@ swfdec_rtmp_rpc_do_send (SwfdecRtmpRpc *rpc, SwfdecAsValue name,
buffer = swfdec_rtmp_rpc_encode (swfdec_gc_object_get_context (rpc->conn),
name, id, special, argc, argv);
- packet = swfdec_rtmp_packet_new (SWFDEC_RTMP_PACKET_INVOKE,
+ packet = swfdec_rtmp_packet_new (0, 0, SWFDEC_RTMP_PACKET_INVOKE,
swfdec_rtmp_rpc_update_last_send (rpc), buffer);
swfdec_buffer_unref (buffer);
empty = g_queue_is_empty (rpc->packets);
@@ -137,7 +137,7 @@ swfdec_rtmp_rpc_receive_reply (SwfdecRtmpRpc *rpc,
}
}
-static void
+static gboolean
swfdec_rtmp_rpc_receive_call (SwfdecRtmpRpc *rpc, SwfdecAmfContext *cx,
SwfdecAsValue val, SwfdecBits *bits)
{
@@ -149,7 +149,7 @@ swfdec_rtmp_rpc_receive_call (SwfdecRtmpRpc *rpc, SwfdecAmfContext *cx,
name = swfdec_as_value_to_string (context, val);
if (!swfdec_amf_decode (cx, bits, &val)) {
SWFDEC_ERROR ("could not decode reply id");
- return;
+ return FALSE;
}
id = swfdec_as_value_to_integer (context, val);
@@ -160,64 +160,69 @@ swfdec_rtmp_rpc_receive_call (SwfdecRtmpRpc *rpc, SwfdecAmfContext *cx,
if (!swfdec_amf_decode (cx, bits, &args[i])) {
SWFDEC_ERROR ("could not decode argument %u", i);
- return;
+ return FALSE;
}
}
- swfdec_as_object_call (rpc->target, name, i, args, &val);
+ swfdec_as_relay_call (rpc->target, name, i, args, &val);
g_free (args);
/* send reply */
if (id) {
swfdec_rtmp_rpc_do_send (rpc, SWFDEC_AS_VALUE_FROM_STRING (SWFDEC_AS_STR__result),
id, val, 0, NULL);
+ return TRUE;
+ } else {
+ return FALSE;
}
}
-void
-swfdec_rtmp_rpc_receive (SwfdecRtmpRpc *rpc,
- const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
+gboolean
+swfdec_rtmp_rpc_receive (SwfdecRtmpRpc *rpc, SwfdecBuffer *buffer)
{
SwfdecAmfContext *cx;
SwfdecAsContext *context;
SwfdecAsValue val;
SwfdecBits bits;
+ gboolean result;
context = swfdec_gc_object_get_context (rpc->conn);
cx = swfdec_amf_context_new (context);
g_assert (context->global);
+ swfdec_bits_init (&bits, buffer);
- switch ((guint) header->type) {
- case SWFDEC_RTMP_PACKET_INVOKE:
- swfdec_bits_init (&bits, buffer);
- if (!swfdec_amf_decode (cx, &bits, &val)) {
- SWFDEC_ERROR ("could not decode call name");
- break;
- }
- if (SWFDEC_AS_VALUE_IS_STRING (val) &&
- SWFDEC_AS_VALUE_GET_STRING (val) == SWFDEC_AS_STR__result) {
- swfdec_rtmp_rpc_receive_reply (rpc, cx, &bits);
- } else {
- swfdec_rtmp_rpc_receive_call (rpc, cx, val, &bits);
- }
- if (swfdec_bits_left (&bits)) {
- SWFDEC_FIXME ("%u bytes left after invoke on channel %u (stream %u)",
- swfdec_bits_left (&bits) / 8, header->channel, header->stream);
- }
- break;
- default:
- SWFDEC_FIXME ("channel %u: what to do with header type %u?",
- header->channel, header->type);
- break;
+ if (!swfdec_amf_decode (cx, &bits, &val)) {
+ SWFDEC_ERROR ("could not decode call name");
+ return FALSE;
+ }
+ if (SWFDEC_AS_VALUE_IS_STRING (val) &&
+ SWFDEC_AS_VALUE_GET_STRING (val) == SWFDEC_AS_STR__result) {
+ swfdec_rtmp_rpc_receive_reply (rpc, cx, &bits);
+ result = FALSE;
+ } else {
+ result = swfdec_rtmp_rpc_receive_call (rpc, cx, val, &bits);
}
swfdec_amf_context_free (cx);
+
+ if (swfdec_bits_left (&bits)) {
+ SWFDEC_FIXME ("%u bytes left after invoke", swfdec_bits_left (&bits) / 8);
+ }
+
+ return result;
}
SwfdecRtmpPacket *
-swfdec_rtmp_rpc_pop (SwfdecRtmpRpc *rpc)
+swfdec_rtmp_rpc_pop (SwfdecRtmpRpc *rpc, gboolean pull_if_pending)
{
+ SwfdecRtmpPacket *packet;
+
g_return_val_if_fail (rpc != NULL, NULL);
- return g_queue_pop_head (rpc->packets);
+ if (!pull_if_pending && rpc->packet_pending)
+ return NULL;
+
+ packet = g_queue_pop_head (rpc->packets);
+ rpc->packet_pending = (packet != NULL);
+ return packet;
}
void
@@ -239,19 +244,18 @@ swfdec_rtmp_rpc_send (SwfdecRtmpRpc *rpc, SwfdecAsValue name,
}
SwfdecRtmpRpc *
-swfdec_rtmp_rpc_new (SwfdecRtmpConnection *conn, SwfdecAsObject *target)
+swfdec_rtmp_rpc_new (SwfdecRtmpConnection *conn, SwfdecAsRelay *target)
{
SwfdecRtmpRpc *rpc;
g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
- g_return_val_if_fail (target != NULL, NULL);
+ g_return_val_if_fail (SWFDEC_IS_AS_RELAY (target), NULL);
- rpc = g_slice_new (SwfdecRtmpRpc);
+ rpc = g_slice_new0 (SwfdecRtmpRpc);
rpc->conn = conn;
rpc->target = target;
rpc->pending = g_hash_table_new (g_direct_hash, g_direct_equal);
rpc->packets = g_queue_new ();
- swfdec_as_context_get_time (swfdec_gc_object_get_context (conn), &rpc->last_send);
return rpc;
}
@@ -269,7 +273,7 @@ swfdec_rtmp_rpc_mark (SwfdecRtmpRpc *rpc)
swfdec_as_object_mark (value);
}
- swfdec_as_object_mark (rpc->target);
+ swfdec_gc_object_mark (rpc->target);
}
void
diff --git a/swfdec/swfdec_rtmp_rpc.h b/swfdec/swfdec_rtmp_rpc.h
index 2dd5a80..3ca46e6 100644
--- a/swfdec/swfdec_rtmp_rpc.h
+++ b/swfdec/swfdec_rtmp_rpc.h
@@ -26,19 +26,18 @@
G_BEGIN_DECLS
-typedef struct _SwfdecRtmpRpc SwfdecRtmpRpc;
-
struct _SwfdecRtmpRpc {
SwfdecRtmpConnection * conn; /* connection to use */
- SwfdecAsObject * target; /* object to call received calls on */
+ SwfdecAsRelay * target; /* object to call received calls on */
guint id; /* last id used for RPC call */
GHashTable * pending; /* int => SwfdecAsObject mapping of calls having pending replies */
GQueue * packets; /* outstanding SwfdecRtmpPackets */
+ gboolean packet_pending; /* if a packet is known to be pending */
GTimeVal last_send; /* time the last call was sent */
};
SwfdecRtmpRpc * swfdec_rtmp_rpc_new (SwfdecRtmpConnection * conn,
- SwfdecAsObject * target);
+ SwfdecAsRelay * target);
void swfdec_rtmp_rpc_free (SwfdecRtmpRpc * rpc);
void swfdec_rtmp_rpc_mark (SwfdecRtmpRpc * rpc);
@@ -49,14 +48,14 @@ SwfdecBuffer * swfdec_rtmp_rpc_encode (SwfdecAsContext * context,
guint argc,
const SwfdecAsValue * argv);
-SwfdecRtmpPacket * swfdec_rtmp_rpc_pop (SwfdecRtmpRpc * rpc);
+SwfdecRtmpPacket * swfdec_rtmp_rpc_pop (SwfdecRtmpRpc * rpc,
+ gboolean pull_if_pending);
void swfdec_rtmp_rpc_send (SwfdecRtmpRpc * rpc,
SwfdecAsValue name,
SwfdecAsObject * reply_to,
guint argc,
const SwfdecAsValue * argv);
-void swfdec_rtmp_rpc_receive (SwfdecRtmpRpc * rpc,
- const SwfdecRtmpHeader *header,
+gboolean swfdec_rtmp_rpc_receive (SwfdecRtmpRpc * rpc,
SwfdecBuffer * buffer);
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
deleted file mode 100644
index 47b7973..0000000
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "swfdec_rtmp_rpc_channel.h"
-
-#include "swfdec_amf.h"
-#include "swfdec_as_strings.h"
-#include "swfdec_debug.h"
-#include "swfdec_rtmp_handshake.h"
-#include "swfdec_rtmp_socket.h"
-#include "swfdec_sandbox.h"
-#include "swfdec_utils.h"
-
-/*** SwfdecRtmpRpcChannel ***/
-
-G_DEFINE_TYPE (SwfdecRtmpRpcChannel, swfdec_rtmp_rpc_channel, SWFDEC_TYPE_RTMP_CHANNEL)
-
-static guint
-swfdec_rtmp_rpc_channel_update_last_send (SwfdecRtmpChannel *channel)
-{
- GTimeVal tv;
- long diff;
-
- swfdec_rtmp_channel_get_time (channel, &tv);
- diff = swfdec_time_val_diff (&channel->timestamp, &tv);
- channel->timestamp = tv;
- return diff;
-}
-
-static void
-swfdec_rtmp_rpc_channel_do_send (SwfdecRtmpRpcChannel *rpc, SwfdecAsValue name,
- guint id, SwfdecAsValue special, guint argc, const SwfdecAsValue *argv)
-{
- SwfdecRtmpChannel *channel;
- SwfdecAsContext *context;
- SwfdecRtmpPacket *packet;
- SwfdecAmfContext *cx;
- SwfdecBuffer *buffer;
- SwfdecBots *bots;
- gboolean empty;
- guint i;
-
- channel = SWFDEC_RTMP_CHANNEL (rpc);
- context = swfdec_gc_object_get_context (channel->conn);
-
- /* prepare buffer to encode */
- cx = swfdec_amf_context_new (context);
- bots = swfdec_bots_new ();
- swfdec_amf_encode (cx, bots, name);
- swfdec_amf_encode (cx, bots, swfdec_as_value_from_number (context, id));
- swfdec_amf_encode (cx, bots, special);
- for (i = 0; i < argc; i++) {
- swfdec_amf_encode (cx, bots, argv[i]);
- }
- buffer = swfdec_bots_close (bots);
- swfdec_amf_context_free (cx);
-
- packet = swfdec_rtmp_packet_new (SWFDEC_RTMP_PACKET_INVOKE,
- swfdec_rtmp_rpc_channel_update_last_send (channel), buffer);
- empty = g_queue_is_empty (rpc->packets);
- g_queue_push_tail (rpc->packets, packet);
- if (empty)
- swfdec_rtmp_channel_send (channel);
-}
-
-static void
-swfdec_rtmp_rpc_channel_receive_reply (SwfdecRtmpChannel *channel,
- SwfdecAmfContext *cx, SwfdecBits *bits)
-{
- SwfdecAsContext *context = swfdec_gc_object_get_context (channel->conn);
- SwfdecAsObject *reply_to;
- SwfdecAsValue val[2], tmp;
- guint id, i;
-
- if (!swfdec_amf_decode (cx, bits, &tmp)) {
- SWFDEC_ERROR ("could not decode reply id");
- return;
- }
- id = swfdec_as_value_to_integer (context, tmp);
-
- for (i = 0; swfdec_bits_left (bits) && i < 2; i++) {
- if (!swfdec_amf_decode (cx, bits, &val[i])) {
- SWFDEC_ERROR ("could not decode reply value");
- return;
- }
- }
- if (swfdec_bits_left (bits)) {
- SWFDEC_FIXME ("more than 2 values in a reply?");
- }
-
- if (id == 1 && channel->conn->handshake) {
- SwfdecRtmpConnection *conn = channel->conn;
-
- /* FIXME: Do something with the result value */
-
- if (i >= 2) {
- swfdec_rtmp_connection_on_status (conn, val[1]);
- } else {
- SWFDEC_ERROR ("no 2nd argument in connect reply");
- }
-
- swfdec_rtmp_handshake_free (conn->handshake);
- conn->handshake = NULL;
- swfdec_rtmp_socket_send (conn->socket);
- } else {
- if (!SWFDEC_AS_VALUE_IS_NULL (val[0])) {
- SWFDEC_FIXME ("first argument in reply is not null?");
- }
- reply_to = g_hash_table_lookup (SWFDEC_RTMP_RPC_CHANNEL (channel)->pending,
- GUINT_TO_POINTER (id));
- if (reply_to == NULL) {
- SWFDEC_ERROR ("no object to send a reply to");
- return;
- }
- g_hash_table_steal (SWFDEC_RTMP_RPC_CHANNEL (channel)->pending, GUINT_TO_POINTER (id));
- swfdec_as_object_call (reply_to, SWFDEC_AS_STR_onResult, 1, &val[1], NULL);
- }
-}
-
-static void
-swfdec_rtmp_rpc_channel_receive_call (SwfdecRtmpChannel *channel,
- SwfdecAmfContext *cx, SwfdecAsValue val, SwfdecBits *bits)
-{
- SwfdecAsContext *context = swfdec_gc_object_get_context (channel->conn);
- SwfdecRtmpRpcChannel *rpc = SWFDEC_RTMP_RPC_CHANNEL (channel);
- const char *name;
- guint id, i;
- SwfdecAsValue *args;
-
- name = swfdec_as_value_to_string (context, val);
- if (!swfdec_amf_decode (cx, bits, &val)) {
- SWFDEC_ERROR ("could not decode reply id");
- return;
- }
- id = swfdec_as_value_to_integer (context, val);
-
- args = NULL;
- for (i = 0; swfdec_bits_left (bits); i++) {
- if ((i % 4) == 0)
- args = g_realloc (args, sizeof (SwfdecAsValue) * (i + 4));
-
- if (!swfdec_amf_decode (cx, bits, &args[i])) {
- SWFDEC_ERROR ("could not decode argument %u", i);
- return;
- }
- }
- swfdec_as_object_call (rpc->target, name, i, args, &val);
- g_free (args);
-
- /* send reply */
- if (id) {
- swfdec_rtmp_rpc_channel_do_send (rpc,
- SWFDEC_AS_VALUE_FROM_STRING (SWFDEC_AS_STR__result), id, val, 0, NULL);
- }
-}
-
-static void
-swfdec_rtmp_rpc_channel_receive (SwfdecRtmpChannel *channel,
- const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
-{
- SwfdecAsContext *context;
- SwfdecAmfContext *cx;
- SwfdecAsValue val;
- SwfdecBits bits;
-
- context = swfdec_gc_object_get_context (channel->conn);
- cx = swfdec_amf_context_new (context);
- swfdec_sandbox_use (channel->conn->sandbox);
- switch ((guint) header->type) {
- case SWFDEC_RTMP_PACKET_INVOKE:
- swfdec_bits_init (&bits, buffer);
- if (!swfdec_amf_decode (cx, &bits, &val)) {
- SWFDEC_ERROR ("could not decode call name");
- break;
- }
- if (SWFDEC_AS_VALUE_IS_STRING (val) &&
- SWFDEC_AS_VALUE_GET_STRING (val) == SWFDEC_AS_STR__result) {
- swfdec_rtmp_rpc_channel_receive_reply (channel, cx, &bits);
- } else {
- swfdec_rtmp_rpc_channel_receive_call (channel, cx, val, &bits);
- }
- break;
- default:
- SWFDEC_FIXME ("channel %u: what to do with header type %u?",
- channel->channel_id, header->type);
- break;
- }
- swfdec_sandbox_unuse (channel->conn->sandbox);
- swfdec_amf_context_free (cx);
-}
-
-static SwfdecRtmpPacket *
-swfdec_rtmp_rpc_channel_send_vfunc (SwfdecRtmpChannel *channel)
-{
- return g_queue_pop_head (SWFDEC_RTMP_RPC_CHANNEL (channel)->packets);
-}
-
-static void
-swfdec_rtmp_rpc_channel_mark (SwfdecRtmpChannel *channel)
-{
- SwfdecRtmpRpcChannel *rpc = SWFDEC_RTMP_RPC_CHANNEL (channel);
- GHashTableIter iter;
- gpointer value;
-
- for (g_hash_table_iter_init (&iter, rpc->pending);
- g_hash_table_iter_next (&iter, NULL, &value);) {
- swfdec_as_object_mark (value);
- }
-
- swfdec_as_object_mark (rpc->target);
-}
-
-static void
-swfdec_rtmp_rpc_channel_dispose (GObject *object)
-{
- SwfdecRtmpRpcChannel *rpc = SWFDEC_RTMP_RPC_CHANNEL (object);
-
- if (rpc->pending) {
- g_hash_table_destroy (rpc->pending);
- rpc->pending = NULL;
- }
- if (rpc->packets) {
- g_queue_foreach (rpc->packets, (GFunc) swfdec_rtmp_packet_free, NULL);
- g_queue_free (rpc->packets);
- rpc->packets = NULL;
- }
-
-
- G_OBJECT_CLASS (swfdec_rtmp_rpc_channel_parent_class)->dispose (object);
-}
-
-static void
-swfdec_rtmp_rpc_channel_class_init (SwfdecRtmpRpcChannelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- SwfdecRtmpChannelClass *channel_class = SWFDEC_RTMP_CHANNEL_CLASS (klass);
-
- object_class->dispose = swfdec_rtmp_rpc_channel_dispose;
-
- channel_class->mark = swfdec_rtmp_rpc_channel_mark;
- channel_class->receive = swfdec_rtmp_rpc_channel_receive;
- channel_class->send = swfdec_rtmp_rpc_channel_send_vfunc;
-}
-
-static void
-swfdec_rtmp_rpc_channel_init (SwfdecRtmpRpcChannel *rpc)
-{
- rpc->pending = g_hash_table_new (g_direct_hash, g_direct_equal);
- rpc->packets = g_queue_new ();
-}
-
-void
-swfdec_rtmp_rpc_channel_send_connect (SwfdecRtmpRpcChannel *rpc,
- SwfdecAsValue connect)
-{
- swfdec_rtmp_rpc_channel_do_send (rpc, SWFDEC_AS_VALUE_FROM_STRING (SWFDEC_AS_STR_connect),
- ++rpc->id, connect, 0, NULL);
-}
-
-void
-swfdec_rtmp_rpc_channel_send (SwfdecRtmpRpcChannel *rpc,
- SwfdecAsValue name, SwfdecAsObject *reply_to,
- guint argc, const SwfdecAsValue *argv)
-{
- guint id;
-
- g_return_if_fail (SWFDEC_IS_RTMP_RPC_CHANNEL (rpc));
- g_return_if_fail (argc == 0 || argv != NULL);
-
- if (reply_to) {
- id = ++rpc->id;
- g_hash_table_insert (rpc->pending, GUINT_TO_POINTER (id), reply_to);
- } else {
- id = 0;
- }
- swfdec_rtmp_rpc_channel_do_send (rpc, name, id, SWFDEC_AS_VALUE_NULL, argc, argv);
-}
-
-SwfdecRtmpChannel *
-swfdec_rtmp_rpc_channel_new (SwfdecRtmpConnection *conn)
-{
- SwfdecRtmpRpcChannel *rpc;
- g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
-
- rpc = g_object_new (SWFDEC_TYPE_RTMP_RPC_CHANNEL, "connection", conn, NULL);
- rpc->target = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (conn));
-
- return SWFDEC_RTMP_CHANNEL (rpc);
-}
-
-void
-swfdec_rtmp_rpc_channel_set_target (SwfdecRtmpRpcChannel *rpc, SwfdecAsObject *object)
-{
- g_return_if_fail (SWFDEC_IS_RTMP_RPC_CHANNEL (rpc));
- g_return_if_fail (object != NULL);
-
- rpc->target = object;
-}
-
diff --git a/swfdec/swfdec_rtmp_rpc_channel.h b/swfdec/swfdec_rtmp_rpc_channel.h
deleted file mode 100644
index b4b69b1..0000000
--- a/swfdec/swfdec_rtmp_rpc_channel.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _SWFDEC_RTMP_RPC_CHANNEL_H_
-#define _SWFDEC_RTMP_RPC_CHANNEL_H_
-
-#include <swfdec/swfdec_ringbuffer.h>
-#include <swfdec/swfdec_rtmp_channel.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _SwfdecRtmpRpcChannel SwfdecRtmpRpcChannel;
-typedef struct _SwfdecRtmpRpcChannelClass SwfdecRtmpRpcChannelClass;
-
-#define SWFDEC_TYPE_RTMP_RPC_CHANNEL (swfdec_rtmp_rpc_channel_get_type())
-#define SWFDEC_IS_RTMP_RPC_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RTMP_RPC_CHANNEL))
-#define SWFDEC_IS_RTMP_RPC_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_RTMP_RPC_CHANNEL))
-#define SWFDEC_RTMP_RPC_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RTMP_RPC_CHANNEL, SwfdecRtmpRpcChannel))
-#define SWFDEC_RTMP_RPC_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_RTMP_RPC_CHANNEL, SwfdecRtmpRpcChannelClass))
-#define SWFDEC_RTMP_RPC_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_RTMP_RPC_CHANNEL, SwfdecRtmpRpcChannelClass))
-
-struct _SwfdecRtmpRpcChannel {
- SwfdecRtmpChannel channel;
-
- SwfdecAsObject * target; /* object to call received calls on */
- guint id; /* last id used for RPC call */
- GHashTable * pending; /* int => SwfdecAsObject mapping of calls having pending replies */
- GQueue * packets; /* outstanding packets */
- GTimeVal last_send; /* time the last call was sent */
-};
-
-struct _SwfdecRtmpRpcChannelClass {
- SwfdecRtmpChannelClass channel_class;
-};
-
-GType swfdec_rtmp_rpc_channel_get_type (void);
-
-SwfdecRtmpChannel * swfdec_rtmp_rpc_channel_new (SwfdecRtmpConnection * conn);
-
-void swfdec_rtmp_rpc_channel_send_connect (SwfdecRtmpRpcChannel * rpc,
- SwfdecAsValue connect);
-void swfdec_rtmp_rpc_channel_send (SwfdecRtmpRpcChannel * rpc,
- SwfdecAsValue name,
- SwfdecAsObject * reply_to,
- guint argc,
- const SwfdecAsValue * argv);
-
-void swfdec_rtmp_rpc_channel_set_target (SwfdecRtmpRpcChannel * rpc,
- SwfdecAsObject * object);
-
-
-G_END_DECLS
-#endif
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 11dfbca..7bacb34 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -27,7 +27,6 @@
#include "swfdec_debug.h"
#include "swfdec_player_internal.h"
-#include "swfdec_rtmp_channel.h"
#include "swfdec_rtmp_handshake.h"
#include "swfdec_rtmp_stream.h"
/* socket implementations for swfdec_rtmp_socket_new() */
@@ -121,9 +120,8 @@ SwfdecBuffer *
swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
{
SwfdecRtmpConnection *conn;
- SwfdecRtmpChannel *channel;
- SwfdecBuffer *buffer;
- GList *walk;
+ SwfdecRtmpPacket *packet;
+ SwfdecBots *bots;
g_return_val_if_fail (SWFDEC_IS_RTMP_SOCKET (socket), NULL);
@@ -132,18 +130,42 @@ swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
if (G_UNLIKELY (conn->handshake))
return swfdec_rtmp_handshake_next_buffer (conn->handshake);
- walk = conn->last_send;
- g_assert (walk);
- do {
- walk = walk->next ? walk->next : conn->channels;
- channel = walk->data;
- buffer = swfdec_rtmp_channel_next_buffer (channel);
- if (buffer != NULL) {
- conn->last_send = walk;
- return buffer;
+ bots = swfdec_bots_new ();
+next_packet:
+ packet = g_queue_pop_head (conn->packets);
+ if (packet == NULL)
+ return NULL;
+ if (packet->header.size == packet->buffer->length) {
+ SwfdecRtmpStream *stream;
+ SwfdecRtmpPacket *next;
+
+ stream = g_hash_table_lookup (conn->streams, GUINT_TO_POINTER (packet->header.stream));
+ if (stream == NULL) {
+ swfdec_rtmp_packet_free (packet);
+ goto next_packet;
+ }
+ next = swfdec_rtmp_stream_sent (stream, packet);
+ if (next == NULL) {
+ swfdec_rtmp_packet_free (packet);
+ goto next_packet;
}
- } while (walk != conn->last_send);
- return NULL;
+ swfdec_rtmp_header_write (&next->header, bots,
+ swfdec_rtmp_header_diff (&next->header, &packet->header));
+ swfdec_rtmp_packet_free (packet);
+ packet = next;
+ packet->buffer->length = 0;
+ } else if (packet->buffer->length == 0) {
+ swfdec_rtmp_header_write (&packet->header, bots, SWFDEC_RTMP_HEADER_12_BYTES);
+ } else {
+ swfdec_rtmp_header_write (&packet->header, bots, SWFDEC_RTMP_HEADER_1_BYTE);
+ }
+ swfdec_bots_put_data (bots, packet->buffer->data + packet->buffer->length,
+ MIN (conn->write_size, packet->header.size - packet->buffer->length));
+ packet->buffer->length += conn->write_size;
+ packet->buffer->length = MIN (packet->buffer->length, packet->header.size);
+
+ g_queue_push_tail (conn->packets, packet);
+ return swfdec_bots_close (bots);
}
void
diff --git a/swfdec/swfdec_rtmp_video_channel.c b/swfdec/swfdec_rtmp_video_channel.c
deleted file mode 100644
index 1f8697f..0000000
--- a/swfdec/swfdec_rtmp_video_channel.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "swfdec_rtmp_video_channel.h"
-
-#include "swfdec_debug.h"
-#include "swfdec_rtmp_socket.h"
-#include "swfdec_video_provider.h"
-
-/*** VIDEO PROVIDER INTERFACE ***/
-
-static cairo_surface_t *
-swfdec_rtmp_video_channel_get_image (SwfdecVideoProvider *prov,
- SwfdecRenderer *renderer, guint *width, guint *height)
-{
- return NULL;
-}
-
-static void
-swfdec_rtmp_video_channel_get_size (SwfdecVideoProvider *prov, guint *width, guint *height)
-{
-}
-
-static void
-swfdec_rtmp_video_channel_video_provider_init (SwfdecVideoProviderInterface *iface)
-{
- iface->get_image = swfdec_rtmp_video_channel_get_image;
- iface->get_size = swfdec_rtmp_video_channel_get_size;
-}
-
-/*** SwfdecRtmpVideoChannel ***/
-
-G_DEFINE_TYPE_WITH_CODE (SwfdecRtmpVideoChannel, swfdec_rtmp_video_channel, SWFDEC_TYPE_RTMP_CHANNEL,
- G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_VIDEO_PROVIDER, swfdec_rtmp_video_channel_video_provider_init))
-
-static void
-swfdec_rtmp_video_channel_receive (SwfdecRtmpChannel *channel,
- const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
-{
-}
-
-static SwfdecRtmpPacket *
-swfdec_rtmp_video_channel_send (SwfdecRtmpChannel *channel)
-{
- return NULL;
-}
-
-static void
-swfdec_rtmp_video_channel_dispose (GObject *object)
-{
- //SwfdecRtmpVideoChannel *conn = SWFDEC_RTMP_VIDEO_CHANNEL (object);
-
- G_OBJECT_CLASS (swfdec_rtmp_video_channel_parent_class)->dispose (object);
-}
-
-static void
-swfdec_rtmp_video_channel_class_init (SwfdecRtmpVideoChannelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- SwfdecRtmpChannelClass *channel_class = SWFDEC_RTMP_CHANNEL_CLASS (klass);
-
- object_class->dispose = swfdec_rtmp_video_channel_dispose;
-
- channel_class->receive = swfdec_rtmp_video_channel_receive;
- channel_class->send = swfdec_rtmp_video_channel_send;
-}
-
-static void
-swfdec_rtmp_video_channel_init (SwfdecRtmpVideoChannel *command)
-{
-}
-
-SwfdecRtmpChannel *
-swfdec_rtmp_video_channel_new (SwfdecRtmpConnection *conn)
-{
- g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
-
- return g_object_new (SWFDEC_TYPE_RTMP_VIDEO_CHANNEL, "connection", conn, NULL);
-}
diff --git a/swfdec/swfdec_rtmp_video_channel.h b/swfdec/swfdec_rtmp_video_channel.h
deleted file mode 100644
index 49f0b15..0000000
--- a/swfdec/swfdec_rtmp_video_channel.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _SWFDEC_RTMP_VIDEO_CHANNEL_H_
-#define _SWFDEC_RTMP_VIDEO_CHANNEL_H_
-
-#include <swfdec/swfdec_rtmp_channel.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _SwfdecRtmpVideoChannel SwfdecRtmpVideoChannel;
-typedef struct _SwfdecRtmpVideoChannelClass SwfdecRtmpVideoChannelClass;
-
-#define SWFDEC_TYPE_RTMP_VIDEO_CHANNEL (swfdec_rtmp_video_channel_get_type())
-#define SWFDEC_IS_RTMP_VIDEO_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL))
-#define SWFDEC_IS_RTMP_VIDEO_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL))
-#define SWFDEC_RTMP_VIDEO_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL, SwfdecRtmpVideoChannel))
-#define SWFDEC_RTMP_VIDEO_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL, SwfdecRtmpVideoChannelClass))
-#define SWFDEC_RTMP_VIDEO_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL, SwfdecRtmpVideoChannelClass))
-
-struct _SwfdecRtmpVideoChannel {
- SwfdecRtmpChannel channel;
-};
-
-struct _SwfdecRtmpVideoChannelClass {
- SwfdecRtmpChannelClass channel_class;
-};
-
-GType swfdec_rtmp_video_channel_get_type (void);
-
-SwfdecRtmpChannel * swfdec_rtmp_video_channel_new (SwfdecRtmpConnection * conn);
-
-
-G_END_DECLS
-#endif
commit 1152a1385217cc070888a2e6a86c85bda253bad6
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 23:58:27 2008 +0100
change handshake to not be a channel anymore
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 38d4990..b64264b 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -134,10 +134,11 @@ libswfdec_source_files = \
swfdec_rtmp_channel.c \
swfdec_rtmp_control_channel.c \
swfdec_rtmp_connection.c \
- swfdec_rtmp_handshake_channel.c \
+ swfdec_rtmp_handshake.c \
swfdec_rtmp_header.c \
swfdec_rtmp_packet.c \
swfdec_rtmp_rpc_channel.c \
+ swfdec_rtmp_rpc.c \
swfdec_rtmp_socket.c \
swfdec_rtmp_socket_rtmp.c \
swfdec_rtmp_stream.c \
@@ -335,10 +336,11 @@ noinst_HEADERS = \
swfdec_rtmp_channel.h \
swfdec_rtmp_control_channel.h \
swfdec_rtmp_connection.h \
- swfdec_rtmp_handshake_channel.h \
+ swfdec_rtmp_handshake.h \
swfdec_rtmp_header.h \
swfdec_rtmp_packet.h \
swfdec_rtmp_rpc_channel.h \
+ swfdec_rtmp_rpc.h \
swfdec_rtmp_socket.h \
swfdec_rtmp_socket_rtmp.h \
swfdec_rtmp_stream.h \
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index e5042de..fcf3418 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -29,7 +29,7 @@
#include "swfdec_bots.h"
#include "swfdec_debug.h"
#include "swfdec_rtmp_control_channel.h"
-#include "swfdec_rtmp_handshake_channel.h"
+#include "swfdec_rtmp_handshake.h"
#include "swfdec_rtmp_rpc_channel.h"
#include "swfdec_rtmp_socket.h"
#include "swfdec_rtmp_stream.h"
@@ -145,7 +145,8 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
if (conn->error)
return;
- conn->handshake = swfdec_rtmp_handshake_channel_new (conn);
+ conn->handshake = swfdec_rtmp_handshake_new (conn);
+
channel = swfdec_rtmp_control_channel_new (conn);
swfdec_rtmp_channel_register (channel, 2, 0);
g_object_unref (channel);
@@ -154,8 +155,7 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
g_object_unref (channel);
conn->last_send = conn->channels;
- swfdec_rtmp_handshake_channel_start (SWFDEC_RTMP_HANDSHAKE_CHANNEL (
- swfdec_rtmp_connection_get_handshake_channel (conn)));
+ swfdec_rtmp_socket_send (conn->socket);
}
void
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index eb37958..2a900df 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -33,6 +33,7 @@ G_BEGIN_DECLS
/* forward declarations */
typedef struct _SwfdecRtmpChannel SwfdecRtmpChannel;
+typedef struct _SwfdecRtmpHandshake SwfdecRtmpHandshake;
typedef struct _SwfdecRtmpSocket SwfdecRtmpSocket;
typedef struct _SwfdecRtmpStream SwfdecRtmpStream;
@@ -54,7 +55,7 @@ struct _SwfdecRtmpConnection {
SwfdecRtmpSocket * socket; /* socket we're using for read/write */
GList * channels; /* list of channels in use by this connection (ordered by channel) */
GList * last_send; /* list entry of last channel sent to */
- SwfdecRtmpChannel * handshake; /* channel used for doing initial handshake or NULL */
+ SwfdecRtmpHandshake * handshake; /* structure used for doing initial handshake or NULL */
char * error; /* NULL or debug string for error message */
GHashTable * incoming; /* channel id => incoming packets */
GHashTable * streams; /* stream id => stream */
@@ -93,7 +94,6 @@ void swfdec_rtmp_register_stream (SwfdecRtmpConnection * conn,
void swfdec_rtmp_unregister_stream (SwfdecRtmpConnection * conn,
guint id);
-#define swfdec_rtmp_connection_get_handshake_channel(conn) ((conn)->handshake)
#define swfdec_rtmp_connection_get_command_channel(conn) (swfdec_rtmp_connection_get_channel (conn, 2))
#define swfdec_rtmp_connection_get_rpc_channel(conn) (swfdec_rtmp_connection_get_channel (conn, 3))
diff --git a/swfdec/swfdec_rtmp_handshake.c b/swfdec/swfdec_rtmp_handshake.c
new file mode 100644
index 0000000..df3d877
--- /dev/null
+++ b/swfdec/swfdec_rtmp_handshake.c
@@ -0,0 +1,248 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_rtmp_handshake.h"
+
+#include <string.h>
+
+#include "swfdec_as_internal.h"
+#include "swfdec_as_strings.h"
+#include "swfdec_debug.h"
+#include "swfdec_player_internal.h"
+#include "swfdec_rtmp_rpc.h"
+#include "swfdec_rtmp_socket.h"
+#include "swfdec_utils.h"
+
+static SwfdecBuffer *
+swfdec_rtmp_handshake_create (SwfdecAsContext *context)
+{
+ SwfdecBots *bots;
+ GTimeVal tv;
+ guint i, x;
+
+ swfdec_as_context_get_time (context, &tv);
+ x = swfdec_time_val_diff (&context->start_time, &tv);
+
+ bots = swfdec_bots_new ();
+ swfdec_bots_prepare_bytes (bots, 1 + 1536);
+ swfdec_bots_put_u8 (bots, 3);
+ swfdec_bots_put_bu32 (bots, x);
+ swfdec_bots_put_bu32 (bots, 0);
+ for (i = 0; i < 1528 / 2; i++) {
+ x = (x * 0xB8CD75 + 1) & 0xFF;
+ swfdec_bots_put_bu16 (bots, x);
+ }
+ g_assert (swfdec_bots_get_bytes (bots) == 1537);
+ return swfdec_bots_close (bots);
+}
+
+SwfdecRtmpHandshake *
+swfdec_rtmp_handshake_new (SwfdecRtmpConnection *conn)
+{
+ SwfdecRtmpHandshake *shake;
+
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+
+ shake = g_slice_new0 (SwfdecRtmpHandshake);
+ shake->conn = conn;
+
+ shake->next_buffer = swfdec_rtmp_handshake_create (swfdec_gc_object_get_context (conn));
+ shake->initial = swfdec_buffer_new_subbuffer (shake->next_buffer, 1, 1536);
+
+ return shake;
+}
+
+void
+swfdec_rtmp_handshake_free (SwfdecRtmpHandshake *shake)
+{
+ g_return_if_fail (shake != NULL);
+
+ if (shake->next_buffer)
+ swfdec_buffer_unref (shake->next_buffer);
+ if (shake->initial)
+ swfdec_buffer_unref (shake->initial);
+
+ g_slice_free (SwfdecRtmpHandshake, shake);
+}
+
+SwfdecBuffer *
+swfdec_rtmp_handshake_next_buffer (SwfdecRtmpHandshake *shake)
+{
+ SwfdecBuffer *buffer;
+
+ g_return_val_if_fail (shake != NULL, NULL);
+
+ if (shake->next_buffer == NULL)
+ return NULL;
+
+ buffer = shake->next_buffer;
+ shake->next_buffer = NULL;
+
+ return buffer;
+}
+
+static SwfdecBuffer *
+swfdec_rtmp_handshake_create_connect (SwfdecRtmpHandshake *shake)
+{
+ SwfdecRtmpConnection *conn;
+ SwfdecAsContext *cx;
+ /* send connect command. Equivalent to:
+ * nc.call ("connect", null, { ... }); */
+ SwfdecAsObject *o;
+ SwfdecAsValue val;
+ const SwfdecURL *url;
+
+ conn = shake->conn;
+ cx = swfdec_gc_object_get_context (conn);
+ o = swfdec_as_object_new_empty (cx);
+
+ /* app */
+ SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx,
+ swfdec_url_get_path (conn->url) ? swfdec_url_get_path (conn->url) : ""));
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_app, &val);
+
+ /* swfUrl */
+ /* FIXME: which URL do we display here actually? */
+ url = SWFDEC_PLAYER (cx)->priv->url;
+ if (swfdec_url_has_protocol (url, "file")) {
+ const char *s = swfdec_url_get_path (url);
+ g_assert (s); /* files must have a path */
+ s = strrchr (s, '/');
+ g_assert (s); /* a full path even */
+ SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx,
+ g_strconcat ("file://", s + 1, NULL)));
+ } else {
+ SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx,
+ swfdec_url_get_url (SWFDEC_PLAYER (cx)->priv->url)));
+ }
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_swfUrl, &val);
+
+ /* tcUrl */
+ SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx,
+ swfdec_url_get_url (conn->url)));
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_tcUrl, &val);
+
+ /* pageUrl */
+ SWFDEC_AS_VALUE_SET_UNDEFINED (&val);
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_pageUrl, &val);
+
+ /* flashVer */
+ SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx,
+ SWFDEC_PLAYER (cx)->priv->system->version));
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_flashVer, &val);
+
+ /* fpad */
+ val = SWFDEC_AS_VALUE_TRUE;
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_fpad, &val);
+
+ /* FIXME: reverse engineer the values used here */
+ /* audioCodecs */
+ val = swfdec_as_value_from_number (cx, 615);
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_audioCodecs, &val);
+
+ /* FIXME: reverse engineer the values used here */
+ /* videoCodecs */
+ val = swfdec_as_value_from_number (cx, 124);
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_videoCodecs, &val);
+
+ /* videoFunction */
+ val = swfdec_as_value_from_number (cx, 1);
+ swfdec_as_object_set_variable (o, SWFDEC_AS_STR_videoFunction, &val);
+
+ return swfdec_rtmp_rpc_encode (cx, SWFDEC_AS_VALUE_FROM_STRING (SWFDEC_AS_STR_connect),
+ 1, SWFDEC_AS_VALUE_FROM_OBJECT (o), 0, NULL);
+}
+
+gboolean
+swfdec_rtmp_handshake_receive (SwfdecRtmpHandshake *shake,
+ SwfdecBufferQueue *queue)
+{
+ SwfdecRtmpConnection *conn;
+ SwfdecRtmpHeader header;
+ SwfdecBuffer *buffer;
+ SwfdecBots *bots;
+ guint i;
+
+ g_return_val_if_fail (shake != NULL, FALSE);
+ g_return_val_if_fail (queue != NULL, FALSE);
+
+ if (shake->next_buffer != NULL)
+ return TRUE;
+
+ if (shake->initial == NULL)
+ return FALSE;
+
+ if (swfdec_buffer_queue_get_depth (queue) < 1536 * 2 + 1)
+ return TRUE;
+
+ conn = shake->conn;
+
+ /* check first byte is 0x3 */
+ buffer = swfdec_buffer_queue_pull (queue, 1);
+ if (buffer->data[0] != 0x3) {
+ swfdec_rtmp_connection_error (conn,
+ "handshake data is wrong, closing connection");
+ swfdec_buffer_unref (buffer);
+ return FALSE;
+ }
+ swfdec_buffer_unref (buffer);
+
+ /* send back next 1536 bytes verbatim */
+ bots = swfdec_bots_new ();
+ buffer = swfdec_buffer_queue_pull (queue, 1536);
+ swfdec_bots_put_buffer (bots, buffer);
+ swfdec_buffer_unref (buffer);
+
+ /* compare last 1536 bytes to be equal to initial handshake */
+ buffer = swfdec_buffer_queue_pull (queue, 1536);
+ if (memcmp (buffer->data, shake->initial->data, 1536) != 0) {
+ swfdec_rtmp_connection_error (conn,
+ "handshake reply packet is wrong, closing connection");
+ swfdec_buffer_unref (buffer);
+ swfdec_bots_free (bots);
+ return FALSE;
+ }
+ swfdec_buffer_unref (buffer);
+ swfdec_buffer_unref (shake->initial);
+ shake->initial = NULL;
+
+ /* send connect command */
+ buffer = swfdec_rtmp_handshake_create_connect (shake);
+ header.channel = 3;
+ header.type = SWFDEC_RTMP_PACKET_INVOKE;
+ header.timestamp = 0;
+ header.size = buffer->length;
+ header.stream = 0;
+ swfdec_rtmp_header_write (&header, bots, SWFDEC_RTMP_HEADER_12_BYTES);
+ for (i = 0; i < buffer->length; i += SWFDEC_RTMP_BLOCK_SIZE) {
+ if (i > 0)
+ swfdec_bots_put_u8 (bots, 0xC3);
+ swfdec_bots_put_data (bots, buffer->data + i,
+ MIN (SWFDEC_RTMP_BLOCK_SIZE, buffer->length - i));
+ }
+
+ shake->next_buffer = swfdec_bots_close (bots);
+ swfdec_rtmp_socket_send (conn->socket);
+ return TRUE;
+}
+
diff --git a/swfdec/swfdec_rtmp_handshake.h b/swfdec/swfdec_rtmp_handshake.h
new file mode 100644
index 0000000..2ceebb6
--- /dev/null
+++ b/swfdec/swfdec_rtmp_handshake.h
@@ -0,0 +1,46 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SWFDEC_RTMP_HANDSHAKE_H_
+#define _SWFDEC_RTMP_HANDSHAKE_H_
+
+#include <swfdec/swfdec_rtmp_connection.h>
+
+G_BEGIN_DECLS
+
+
+struct _SwfdecRtmpHandshake {
+ SwfdecRtmpConnection * conn; /* connection we use */
+
+ SwfdecBuffer * next_buffer; /* buffer we want to send */
+ SwfdecBuffer * initial; /* initial buffer that was sent */
+};
+
+GType swfdec_rtmp_handshake_get_type (void);
+
+SwfdecRtmpHandshake * swfdec_rtmp_handshake_new (SwfdecRtmpConnection * conn);
+void swfdec_rtmp_handshake_free (SwfdecRtmpHandshake * shake);
+
+SwfdecBuffer * swfdec_rtmp_handshake_next_buffer (SwfdecRtmpHandshake * shake);
+gboolean swfdec_rtmp_handshake_receive (SwfdecRtmpHandshake * shake,
+ SwfdecBufferQueue * queue);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_rtmp_handshake_channel.c b/swfdec/swfdec_rtmp_handshake_channel.c
deleted file mode 100644
index ec39e23..0000000
--- a/swfdec/swfdec_rtmp_handshake_channel.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "swfdec_rtmp_handshake_channel.h"
-
-#include <string.h>
-
-#include "swfdec_as_internal.h"
-#include "swfdec_as_strings.h"
-#include "swfdec_debug.h"
-#include "swfdec_player_internal.h"
-#include "swfdec_rtmp_rpc_channel.h"
-#include "swfdec_rtmp_socket.h"
-#include "swfdec_utils.h"
-
-/*** SwfdecRtmpHandshakeChannel ***/
-
-G_DEFINE_TYPE (SwfdecRtmpHandshakeChannel, swfdec_rtmp_handshake_channel, SWFDEC_TYPE_RTMP_CHANNEL)
-
-static SwfdecBuffer *
-swfdec_rtmp_handshake_create (SwfdecAsContext *context)
-{
- SwfdecBots *bots;
- GTimeVal tv;
- guint i, x;
-
- swfdec_as_context_get_time (context, &tv);
- x = swfdec_time_val_diff (&context->start_time, &tv);
-
- bots = swfdec_bots_new ();
- swfdec_bots_prepare_bytes (bots, 1 + 1536);
- swfdec_bots_put_u8 (bots, 3);
- swfdec_bots_put_bu32 (bots, x);
- swfdec_bots_put_bu32 (bots, 0);
- for (i = 0; i < 1528 / 2; i++) {
- x = (x * 0xB8CD75 + 1) & 0xFF;
- swfdec_bots_put_bu16 (bots, x);
- }
- g_assert (swfdec_bots_get_bytes (bots) == 1537);
- return swfdec_bots_close (bots);
-}
-
-static void
-swfdec_rtmp_handshake_channel_push_connect (SwfdecRtmpHandshakeChannel *shake)
-{
- SwfdecRtmpConnection *conn;
- SwfdecAsContext *cx;
- /* send connect command. Equivalent to:
- * nc.call ("connect", null, { ... }); */
- SwfdecAsObject *o;
- SwfdecAsValue val;
- const SwfdecURL *url;
-
- conn = SWFDEC_RTMP_CHANNEL (shake)->conn;
- cx = swfdec_gc_object_get_context (conn);
- o = swfdec_as_object_new_empty (cx);
-
- /* app */
- SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx,
- swfdec_url_get_path (conn->url) ? swfdec_url_get_path (conn->url) : ""));
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_app, &val);
-
- /* swfUrl */
- /* FIXME: which URL do we display here actually? */
- url = SWFDEC_PLAYER (cx)->priv->url;
- if (swfdec_url_has_protocol (url, "file")) {
- const char *s = swfdec_url_get_path (url);
- g_assert (s); /* files must have a path */
- s = strrchr (s, '/');
- g_assert (s); /* a full path even */
- SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx,
- g_strconcat ("file://", s + 1, NULL)));
- } else {
- SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx,
- swfdec_url_get_url (SWFDEC_PLAYER (cx)->priv->url)));
- }
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_swfUrl, &val);
-
- /* tcUrl */
- SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx,
- swfdec_url_get_url (conn->url)));
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_tcUrl, &val);
-
- /* pageUrl */
- SWFDEC_AS_VALUE_SET_UNDEFINED (&val);
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_pageUrl, &val);
-
- /* flashVer */
- SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx,
- SWFDEC_PLAYER (cx)->priv->system->version));
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_flashVer, &val);
-
- /* fpad */
- val = SWFDEC_AS_VALUE_TRUE;
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_fpad, &val);
-
- /* FIXME: reverse engineer the values used here */
- /* audioCodecs */
- val = swfdec_as_value_from_number (cx, 615);
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_audioCodecs, &val);
-
- /* FIXME: reverse engineer the values used here */
- /* videoCodecs */
- val = swfdec_as_value_from_number (cx, 124);
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_videoCodecs, &val);
-
- /* videoFunction */
- val = swfdec_as_value_from_number (cx, 1);
- swfdec_as_object_set_variable (o, SWFDEC_AS_STR_videoFunction, &val);
-
- swfdec_rtmp_rpc_channel_send_connect (SWFDEC_RTMP_RPC_CHANNEL (
- swfdec_rtmp_connection_get_rpc_channel (conn)), SWFDEC_AS_VALUE_FROM_OBJECT (o));
-}
-
-void
-swfdec_rtmp_handshake_channel_start (SwfdecRtmpHandshakeChannel *shake)
-{
- SwfdecRtmpChannel *channel;
- SwfdecRtmpConnection *conn;
- SwfdecBuffer *buffer;
-
- g_return_if_fail (SWFDEC_IS_RTMP_HANDSHAKE_CHANNEL (shake));
- g_return_if_fail (shake->initial == NULL);
- g_return_if_fail (shake->reply == NULL);
-
- channel = SWFDEC_RTMP_CHANNEL (shake);
- conn = channel->conn;
-
- buffer = swfdec_rtmp_handshake_create (swfdec_gc_object_get_context (conn));
- shake->initial = swfdec_buffer_new_subbuffer (buffer, 1, 1536);
- swfdec_buffer_queue_push (channel->send_queue, buffer);
- swfdec_rtmp_socket_send (conn->socket);
- swfdec_rtmp_handshake_channel_push_connect (shake);
-}
-
-/* FIXME: This is a rather large hack where we only send the connect command
- * but not anything else until we got a reply to the connect command */
-static void
-swfdec_rtmp_handshake_channel_redirect_connect (SwfdecRtmpHandshakeChannel *shake)
-{
- SwfdecRtmpConnection *conn = SWFDEC_RTMP_CHANNEL (shake)->conn;
- SwfdecRtmpChannel *rpc = swfdec_rtmp_connection_get_rpc_channel (conn);
- SwfdecBuffer *buffer;
-
- buffer = swfdec_rtmp_channel_next_buffer (rpc);
- swfdec_buffer_queue_push (SWFDEC_RTMP_CHANNEL (shake)->send_queue, buffer);
- while ((buffer = swfdec_buffer_queue_pull_buffer (rpc->send_queue))) {
- swfdec_buffer_queue_push (SWFDEC_RTMP_CHANNEL (shake)->send_queue, buffer);
- }
- swfdec_rtmp_header_invalidate (&rpc->send_cache);
-}
-
-gboolean
-swfdec_rtmp_handshake_channel_receive (SwfdecRtmpHandshakeChannel *shake,
- SwfdecBufferQueue *queue)
-{
- SwfdecRtmpConnection *conn;
- SwfdecBuffer *buffer;
-
- g_return_val_if_fail (SWFDEC_IS_RTMP_HANDSHAKE_CHANNEL (shake), FALSE);
- g_return_val_if_fail (queue != NULL, FALSE);
-
- if (shake->initial == NULL || shake->reply != NULL)
- return FALSE;
-
- if (swfdec_buffer_queue_get_depth (queue) < 1536 * 2 + 1)
- return FALSE;
-
- conn = SWFDEC_RTMP_CHANNEL (shake)->conn;
-
- /* check first byte is 0x3 */
- buffer = swfdec_buffer_queue_pull (queue, 1);
- if (buffer->data[0] != 0x3) {
- swfdec_rtmp_connection_error (conn,
- "handshake data is wrong, closing connection");
- swfdec_buffer_unref (buffer);
- return FALSE;
- }
- swfdec_buffer_unref (buffer);
-
- /* send back next 1536 bytes verbatim */
- shake->reply = swfdec_buffer_queue_pull (queue, 1536);
- swfdec_buffer_queue_push (SWFDEC_RTMP_CHANNEL (shake)->send_queue, swfdec_buffer_ref (shake->reply));
-
- /* compare last 1536 bytes to be equal to initial handshake */
- buffer = swfdec_buffer_queue_pull (queue, 1536);
- if (memcmp (buffer->data, shake->initial->data, 1536) != 0) {
- swfdec_rtmp_connection_error (conn,
- "handshake reply packet is wrong, closing connection");
- swfdec_buffer_unref (buffer);
- return FALSE;
- }
- swfdec_buffer_unref (buffer);
-
- /* send connect command */
- swfdec_rtmp_handshake_channel_redirect_connect (shake);
-
- swfdec_rtmp_socket_send (conn->socket);
- return FALSE;
-}
-
-static void
-swfdec_rtmp_handshake_channel_dont_receive (SwfdecRtmpChannel *channel,
- const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
-{
- g_critical ("This function should never be called");
-}
-
-static void
-swfdec_rtmp_handshake_channel_dispose (GObject *object)
-{
- SwfdecRtmpHandshakeChannel *shake = SWFDEC_RTMP_HANDSHAKE_CHANNEL (object);
-
- if (shake->initial) {
- swfdec_buffer_unref (shake->initial);
- shake->initial = NULL;
- }
- if (shake->reply) {
- swfdec_buffer_unref (shake->reply);
- shake->reply = NULL;
- }
-
- G_OBJECT_CLASS (swfdec_rtmp_handshake_channel_parent_class)->dispose (object);
-}
-
-static void
-swfdec_rtmp_handshake_channel_class_init (SwfdecRtmpHandshakeChannelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- SwfdecRtmpChannelClass *channel_class = SWFDEC_RTMP_CHANNEL_CLASS (klass);
-
- object_class->dispose = swfdec_rtmp_handshake_channel_dispose;
-
- channel_class->receive = swfdec_rtmp_handshake_channel_dont_receive;
-}
-
-static void
-swfdec_rtmp_handshake_channel_init (SwfdecRtmpHandshakeChannel *command)
-{
-}
-
-void
-swfdec_rtmp_handshake_channel_connected (SwfdecRtmpHandshakeChannel *shake,
- guint argc, const SwfdecAsValue *argv)
-{
- SwfdecRtmpConnection *conn;
-
- g_return_if_fail (SWFDEC_IS_RTMP_HANDSHAKE_CHANNEL (shake));
-
- conn = SWFDEC_RTMP_CHANNEL (shake)->conn;
-
- /* FIXME: Do something with the result value */
-
- if (argc >= 2) {
- swfdec_rtmp_connection_on_status (conn, argv[1]);
- } else {
- SWFDEC_ERROR ("no 2nd argument in connect reply");
- }
-
- conn->handshake = NULL;
- swfdec_rtmp_socket_send (conn->socket);
- g_object_unref (shake);
-}
-
-SwfdecRtmpChannel *
-swfdec_rtmp_handshake_channel_new (SwfdecRtmpConnection *conn)
-{
- g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
-
- return g_object_new (SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL, "connection", conn, NULL);
-}
diff --git a/swfdec/swfdec_rtmp_handshake_channel.h b/swfdec/swfdec_rtmp_handshake_channel.h
deleted file mode 100644
index f5bcd0b..0000000
--- a/swfdec/swfdec_rtmp_handshake_channel.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _SWFDEC_RTMP_HANDSHAKE_CHANNEL_H_
-#define _SWFDEC_RTMP_HANDSHAKE_CHANNEL_H_
-
-#include <swfdec/swfdec_rtmp_channel.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _SwfdecRtmpHandshakeChannel SwfdecRtmpHandshakeChannel;
-typedef struct _SwfdecRtmpHandshakeChannelClass SwfdecRtmpHandshakeChannelClass;
-
-#define SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL (swfdec_rtmp_handshake_channel_get_type())
-#define SWFDEC_IS_RTMP_HANDSHAKE_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL))
-#define SWFDEC_IS_RTMP_HANDSHAKE_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL))
-#define SWFDEC_RTMP_HANDSHAKE_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL, SwfdecRtmpHandshakeChannel))
-#define SWFDEC_RTMP_HANDSHAKE_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL, SwfdecRtmpHandshakeChannelClass))
-#define SWFDEC_RTMP_HANDSHAKE_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL, SwfdecRtmpHandshakeChannelClass))
-
-struct _SwfdecRtmpHandshakeChannel {
- SwfdecRtmpChannel channel;
-
- SwfdecBuffer * initial; /* initial buffer that was sent */
- SwfdecBuffer * reply; /* reply that was gotten */
-};
-
-struct _SwfdecRtmpHandshakeChannelClass {
- SwfdecRtmpChannelClass channel_class;
-};
-
-GType swfdec_rtmp_handshake_channel_get_type (void);
-
-SwfdecRtmpChannel * swfdec_rtmp_handshake_channel_new (SwfdecRtmpConnection * conn);
-
-void swfdec_rtmp_handshake_channel_start (SwfdecRtmpHandshakeChannel * channel);
-gboolean swfdec_rtmp_handshake_channel_receive (SwfdecRtmpHandshakeChannel * channel,
- SwfdecBufferQueue * queue);
-void swfdec_rtmp_handshake_channel_connected (SwfdecRtmpHandshakeChannel * shake,
- guint argc,
- const SwfdecAsValue * argv);
-
-
-G_END_DECLS
-#endif
diff --git a/swfdec/swfdec_rtmp_rpc.c b/swfdec/swfdec_rtmp_rpc.c
new file mode 100644
index 0000000..984552a
--- /dev/null
+++ b/swfdec/swfdec_rtmp_rpc.c
@@ -0,0 +1,291 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_rtmp_rpc.h"
+
+#include "swfdec_amf.h"
+#include "swfdec_as_strings.h"
+#include "swfdec_debug.h"
+#include "swfdec_rtmp_handshake.h"
+#include "swfdec_rtmp_packet.h"
+#include "swfdec_rtmp_socket.h"
+#include "swfdec_utils.h"
+
+SwfdecBuffer *
+swfdec_rtmp_rpc_encode (SwfdecAsContext *context, SwfdecAsValue name,
+ guint reply_id, SwfdecAsValue special, guint argc, const SwfdecAsValue *argv)
+{
+ SwfdecAmfContext *cx;
+ SwfdecBuffer *buffer;
+ SwfdecBots *bots;
+ guint i;
+
+ cx = swfdec_amf_context_new (context);
+ bots = swfdec_bots_new ();
+ swfdec_amf_encode (cx, bots, name);
+ swfdec_amf_encode (cx, bots, swfdec_as_value_from_number (context, reply_id));
+ swfdec_amf_encode (cx, bots, special);
+ for (i = 0; i < argc; i++) {
+ swfdec_amf_encode (cx, bots, argv[i]);
+ }
+ buffer = swfdec_bots_close (bots);
+ swfdec_amf_context_free (cx);
+
+ return buffer;
+}
+
+static guint
+swfdec_rtmp_rpc_update_last_send (SwfdecRtmpRpc *rpc)
+{
+ GTimeVal tv;
+ long diff;
+
+ swfdec_as_context_get_time (swfdec_gc_object_get_context (rpc->conn), &tv);
+ diff = swfdec_time_val_diff (&rpc->last_send, &tv);
+ rpc->last_send = tv;
+ return diff;
+}
+
+static void
+swfdec_rtmp_rpc_do_send (SwfdecRtmpRpc *rpc, SwfdecAsValue name,
+ guint id, SwfdecAsValue special, guint argc, const SwfdecAsValue *argv)
+{
+ SwfdecRtmpPacket *packet;
+ SwfdecBuffer *buffer;
+ gboolean empty;
+
+ buffer = swfdec_rtmp_rpc_encode (swfdec_gc_object_get_context (rpc->conn),
+ name, id, special, argc, argv);
+
+ packet = swfdec_rtmp_packet_new (SWFDEC_RTMP_PACKET_INVOKE,
+ swfdec_rtmp_rpc_update_last_send (rpc), buffer);
+ swfdec_buffer_unref (buffer);
+ empty = g_queue_is_empty (rpc->packets);
+ g_queue_push_tail (rpc->packets, packet);
+}
+
+static void
+swfdec_rtmp_rpc_receive_reply (SwfdecRtmpRpc *rpc,
+ SwfdecAmfContext *cx, SwfdecBits *bits)
+{
+ SwfdecAsObject *reply_to;
+ SwfdecAsValue val[2], tmp;
+ guint id, i;
+
+ if (!swfdec_amf_decode (cx, bits, &tmp)) {
+ SWFDEC_ERROR ("could not decode reply id");
+ return;
+ }
+ id = swfdec_as_value_to_integer (swfdec_gc_object_get_context (rpc->conn), tmp);
+
+ for (i = 0; swfdec_bits_left (bits) && i < 2; i++) {
+ if (!swfdec_amf_decode (cx, bits, &val[i])) {
+ SWFDEC_ERROR ("could not decode reply value");
+ return;
+ }
+ }
+ if (swfdec_bits_left (bits)) {
+ SWFDEC_FIXME ("more than 2 values in a reply?");
+ }
+
+ if (id == 1 && rpc->conn->handshake) {
+ SwfdecRtmpConnection *conn = rpc->conn;
+
+ /* FIXME: Do something with the result value */
+
+ if (i >= 2) {
+ swfdec_rtmp_connection_on_status (conn, val[1]);
+ } else {
+ SWFDEC_ERROR ("no 2nd argument in connect reply");
+ }
+
+ swfdec_rtmp_handshake_free (conn->handshake);
+ conn->handshake = NULL;
+ swfdec_rtmp_socket_send (conn->socket);
+ } else {
+ if (!SWFDEC_AS_VALUE_IS_NULL (val[0])) {
+ SWFDEC_FIXME ("first argument in reply is not null?");
+ }
+ reply_to = g_hash_table_lookup (rpc->pending,
+ GUINT_TO_POINTER (id));
+ if (reply_to == NULL) {
+ SWFDEC_ERROR ("no object to send a reply to");
+ return;
+ }
+ g_hash_table_steal (rpc->pending, GUINT_TO_POINTER (id));
+ swfdec_as_object_call (reply_to, SWFDEC_AS_STR_onResult, 1, &val[1], NULL);
+ }
+}
+
+static void
+swfdec_rtmp_rpc_receive_call (SwfdecRtmpRpc *rpc, SwfdecAmfContext *cx,
+ SwfdecAsValue val, SwfdecBits *bits)
+{
+ SwfdecAsContext *context = swfdec_gc_object_get_context (rpc->conn);
+ const char *name;
+ guint id, i;
+ SwfdecAsValue *args;
+
+ name = swfdec_as_value_to_string (context, val);
+ if (!swfdec_amf_decode (cx, bits, &val)) {
+ SWFDEC_ERROR ("could not decode reply id");
+ return;
+ }
+ id = swfdec_as_value_to_integer (context, val);
+
+ args = NULL;
+ for (i = 0; swfdec_bits_left (bits); i++) {
+ if ((i % 4) == 0)
+ args = g_realloc (args, sizeof (SwfdecAsValue) * (i + 4));
+
+ if (!swfdec_amf_decode (cx, bits, &args[i])) {
+ SWFDEC_ERROR ("could not decode argument %u", i);
+ return;
+ }
+ }
+ swfdec_as_object_call (rpc->target, name, i, args, &val);
+ g_free (args);
+
+ /* send reply */
+ if (id) {
+ swfdec_rtmp_rpc_do_send (rpc, SWFDEC_AS_VALUE_FROM_STRING (SWFDEC_AS_STR__result),
+ id, val, 0, NULL);
+ }
+}
+
+void
+swfdec_rtmp_rpc_receive (SwfdecRtmpRpc *rpc,
+ const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
+{
+ SwfdecAmfContext *cx;
+ SwfdecAsContext *context;
+ SwfdecAsValue val;
+ SwfdecBits bits;
+
+ context = swfdec_gc_object_get_context (rpc->conn);
+ cx = swfdec_amf_context_new (context);
+ g_assert (context->global);
+
+ switch ((guint) header->type) {
+ case SWFDEC_RTMP_PACKET_INVOKE:
+ swfdec_bits_init (&bits, buffer);
+ if (!swfdec_amf_decode (cx, &bits, &val)) {
+ SWFDEC_ERROR ("could not decode call name");
+ break;
+ }
+ if (SWFDEC_AS_VALUE_IS_STRING (val) &&
+ SWFDEC_AS_VALUE_GET_STRING (val) == SWFDEC_AS_STR__result) {
+ swfdec_rtmp_rpc_receive_reply (rpc, cx, &bits);
+ } else {
+ swfdec_rtmp_rpc_receive_call (rpc, cx, val, &bits);
+ }
+ if (swfdec_bits_left (&bits)) {
+ SWFDEC_FIXME ("%u bytes left after invoke on channel %u (stream %u)",
+ swfdec_bits_left (&bits) / 8, header->channel, header->stream);
+ }
+ break;
+ default:
+ SWFDEC_FIXME ("channel %u: what to do with header type %u?",
+ header->channel, header->type);
+ break;
+ }
+ swfdec_amf_context_free (cx);
+}
+
+SwfdecRtmpPacket *
+swfdec_rtmp_rpc_pop (SwfdecRtmpRpc *rpc)
+{
+ g_return_val_if_fail (rpc != NULL, NULL);
+
+ return g_queue_pop_head (rpc->packets);
+}
+
+void
+swfdec_rtmp_rpc_send (SwfdecRtmpRpc *rpc, SwfdecAsValue name,
+ SwfdecAsObject *reply_to, guint argc, const SwfdecAsValue *argv)
+{
+ guint id;
+
+ g_return_if_fail (rpc != NULL);
+ g_return_if_fail (argc == 0 || argv != NULL);
+
+ if (reply_to) {
+ id = ++rpc->id;
+ g_hash_table_insert (rpc->pending, GUINT_TO_POINTER (id), reply_to);
+ } else {
+ id = 0;
+ }
+ swfdec_rtmp_rpc_do_send (rpc, name, id, SWFDEC_AS_VALUE_NULL, argc, argv);
+}
+
+SwfdecRtmpRpc *
+swfdec_rtmp_rpc_new (SwfdecRtmpConnection *conn, SwfdecAsObject *target)
+{
+ SwfdecRtmpRpc *rpc;
+
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+ g_return_val_if_fail (target != NULL, NULL);
+
+ rpc = g_slice_new (SwfdecRtmpRpc);
+ rpc->conn = conn;
+ rpc->target = target;
+ rpc->pending = g_hash_table_new (g_direct_hash, g_direct_equal);
+ rpc->packets = g_queue_new ();
+ swfdec_as_context_get_time (swfdec_gc_object_get_context (conn), &rpc->last_send);
+
+ return rpc;
+}
+
+void
+swfdec_rtmp_rpc_mark (SwfdecRtmpRpc *rpc)
+{
+ GHashTableIter iter;
+ gpointer value;
+
+ g_return_if_fail (rpc != NULL);
+
+ for (g_hash_table_iter_init (&iter, rpc->pending);
+ g_hash_table_iter_next (&iter, NULL, &value);) {
+ swfdec_as_object_mark (value);
+ }
+
+ swfdec_as_object_mark (rpc->target);
+}
+
+void
+swfdec_rtmp_rpc_free (SwfdecRtmpRpc *rpc)
+{
+ g_return_if_fail (rpc != NULL);
+
+ if (rpc->pending) {
+ g_hash_table_destroy (rpc->pending);
+ rpc->pending = NULL;
+ }
+ if (rpc->packets) {
+ g_queue_foreach (rpc->packets, (GFunc) swfdec_rtmp_packet_free, NULL);
+ g_queue_free (rpc->packets);
+ rpc->packets = NULL;
+ }
+ g_slice_free (SwfdecRtmpRpc, rpc);
+}
+
diff --git a/swfdec/swfdec_rtmp_rpc.h b/swfdec/swfdec_rtmp_rpc.h
new file mode 100644
index 0000000..2dd5a80
--- /dev/null
+++ b/swfdec/swfdec_rtmp_rpc.h
@@ -0,0 +1,64 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SWFDEC_RTMP_RPC_H_
+#define _SWFDEC_RTMP_RPC_H_
+
+#include <swfdec/swfdec_rtmp_connection.h>
+#include <swfdec/swfdec_rtmp_packet.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecRtmpRpc SwfdecRtmpRpc;
+
+struct _SwfdecRtmpRpc {
+ SwfdecRtmpConnection * conn; /* connection to use */
+ SwfdecAsObject * target; /* object to call received calls on */
+ guint id; /* last id used for RPC call */
+ GHashTable * pending; /* int => SwfdecAsObject mapping of calls having pending replies */
+ GQueue * packets; /* outstanding SwfdecRtmpPackets */
+ GTimeVal last_send; /* time the last call was sent */
+};
+
+SwfdecRtmpRpc * swfdec_rtmp_rpc_new (SwfdecRtmpConnection * conn,
+ SwfdecAsObject * target);
+void swfdec_rtmp_rpc_free (SwfdecRtmpRpc * rpc);
+void swfdec_rtmp_rpc_mark (SwfdecRtmpRpc * rpc);
+
+SwfdecBuffer * swfdec_rtmp_rpc_encode (SwfdecAsContext * context,
+ SwfdecAsValue name,
+ guint reply_id,
+ SwfdecAsValue special,
+ guint argc,
+ const SwfdecAsValue * argv);
+
+SwfdecRtmpPacket * swfdec_rtmp_rpc_pop (SwfdecRtmpRpc * rpc);
+void swfdec_rtmp_rpc_send (SwfdecRtmpRpc * rpc,
+ SwfdecAsValue name,
+ SwfdecAsObject * reply_to,
+ guint argc,
+ const SwfdecAsValue * argv);
+void swfdec_rtmp_rpc_receive (SwfdecRtmpRpc * rpc,
+ const SwfdecRtmpHeader *header,
+ SwfdecBuffer * buffer);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index 241dff8..47b7973 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -26,7 +26,7 @@
#include "swfdec_amf.h"
#include "swfdec_as_strings.h"
#include "swfdec_debug.h"
-#include "swfdec_rtmp_handshake_channel.h"
+#include "swfdec_rtmp_handshake.h"
#include "swfdec_rtmp_socket.h"
#include "swfdec_sandbox.h"
#include "swfdec_utils.h"
@@ -108,10 +108,20 @@ swfdec_rtmp_rpc_channel_receive_reply (SwfdecRtmpChannel *channel,
SWFDEC_FIXME ("more than 2 values in a reply?");
}
- if (id == 1 && swfdec_rtmp_connection_get_handshake_channel (channel->conn)) {
- swfdec_rtmp_handshake_channel_connected (SWFDEC_RTMP_HANDSHAKE_CHANNEL (
- swfdec_rtmp_connection_get_handshake_channel (channel->conn)),
- i, val);
+ if (id == 1 && channel->conn->handshake) {
+ SwfdecRtmpConnection *conn = channel->conn;
+
+ /* FIXME: Do something with the result value */
+
+ if (i >= 2) {
+ swfdec_rtmp_connection_on_status (conn, val[1]);
+ } else {
+ SWFDEC_ERROR ("no 2nd argument in connect reply");
+ }
+
+ swfdec_rtmp_handshake_free (conn->handshake);
+ conn->handshake = NULL;
+ swfdec_rtmp_socket_send (conn->socket);
} else {
if (!SWFDEC_AS_VALUE_IS_NULL (val[0])) {
SWFDEC_FIXME ("first argument in reply is not null?");
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 5232f4b..11dfbca 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -26,8 +26,9 @@
#include <string.h>
#include "swfdec_debug.h"
-#include "swfdec_rtmp_handshake_channel.h"
#include "swfdec_player_internal.h"
+#include "swfdec_rtmp_channel.h"
+#include "swfdec_rtmp_handshake.h"
#include "swfdec_rtmp_stream.h"
/* socket implementations for swfdec_rtmp_socket_new() */
#include "swfdec_rtmp_socket_rtmp.h"
@@ -128,9 +129,8 @@ swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
conn = socket->conn;
- if (G_UNLIKELY (swfdec_rtmp_connection_get_handshake_channel (conn))) {
- return swfdec_buffer_queue_pull_buffer (swfdec_rtmp_connection_get_handshake_channel (conn)->send_queue);
- }
+ if (G_UNLIKELY (conn->handshake))
+ return swfdec_rtmp_handshake_next_buffer (conn->handshake);
walk = conn->last_send;
g_assert (walk);
@@ -161,13 +161,9 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
conn = sock->conn;
- if (G_UNLIKELY (swfdec_rtmp_connection_get_handshake_channel (conn))) {
- SwfdecRtmpHandshakeChannel *shake = SWFDEC_RTMP_HANDSHAKE_CHANNEL (
- swfdec_rtmp_connection_get_handshake_channel (conn));
- if (shake->reply == NULL) {
- while (swfdec_rtmp_handshake_channel_receive (shake, queue));
+ if (G_UNLIKELY (conn->handshake)) {
+ if (swfdec_rtmp_handshake_receive (conn->handshake, queue))
return;
- }
}
do {
commit 75bd1b2ee87e14b106b74c64f06fad7063b215fc
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 19:58:35 2008 +0100
first step in (again) reworking the RTMP handling
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 5a0e33b..38d4990 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -140,6 +140,7 @@ libswfdec_source_files = \
swfdec_rtmp_rpc_channel.c \
swfdec_rtmp_socket.c \
swfdec_rtmp_socket_rtmp.c \
+ swfdec_rtmp_stream.c \
swfdec_rtmp_video_channel.c \
swfdec_sandbox.c \
swfdec_script.c \
@@ -340,6 +341,7 @@ noinst_HEADERS = \
swfdec_rtmp_rpc_channel.h \
swfdec_rtmp_socket.h \
swfdec_rtmp_socket_rtmp.h \
+ swfdec_rtmp_stream.h \
swfdec_rtmp_video_channel.h \
swfdec_sandbox.h \
swfdec_script_internal.h \
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 300842b..e5042de 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -32,10 +32,36 @@
#include "swfdec_rtmp_handshake_channel.h"
#include "swfdec_rtmp_rpc_channel.h"
#include "swfdec_rtmp_socket.h"
+#include "swfdec_rtmp_stream.h"
+
+/*** SwfdecRtmpStream ***/
+
+static void
+swfdec_rtmp_connection_rtmp_stream_receive (SwfdecRtmpStream *stream,
+ const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
+{
+ SwfdecRtmpConnection *conn = SWFDEC_RTMP_CONNECTION (stream);
+ SwfdecRtmpChannel *channel = swfdec_rtmp_connection_get_channel (conn, header->channel);
+ SwfdecRtmpChannelClass *klass;
+
+ if (channel == NULL) {
+ SWFDEC_FIXME ("woot, no channel %u", header->channel);
+ return;
+ }
+ klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
+ klass->receive (channel, header, buffer);
+}
+
+static void
+swfdec_rtmp_connection_rtmp_stream_init (SwfdecRtmpStreamInterface *iface)
+{
+ iface->receive = swfdec_rtmp_connection_rtmp_stream_receive;
+}
/*** SwfdecRtmpConnection ***/
-G_DEFINE_TYPE (SwfdecRtmpConnection, swfdec_rtmp_connection, SWFDEC_TYPE_AS_RELAY)
+G_DEFINE_TYPE_WITH_CODE (SwfdecRtmpConnection, swfdec_rtmp_connection, SWFDEC_TYPE_AS_RELAY,
+ G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_RTMP_STREAM, swfdec_rtmp_connection_rtmp_stream_init))
static void
swfdec_rtmp_connection_mark (SwfdecGcObject *object)
@@ -64,6 +90,15 @@ swfdec_rtmp_connection_dispose (GObject *object)
g_free (conn->error);
conn->error = NULL;
+ if (conn->incoming) {
+ g_hash_table_destroy (conn->incoming);
+ conn->incoming = NULL;
+ }
+ if (conn->streams) {
+ g_hash_table_destroy (conn->streams);
+ conn->streams = NULL;
+ }
+
G_OBJECT_CLASS (swfdec_rtmp_connection_parent_class)->dispose (object);
}
@@ -81,8 +116,14 @@ swfdec_rtmp_connection_class_init (SwfdecRtmpConnectionClass *klass)
static void
swfdec_rtmp_connection_init (SwfdecRtmpConnection *conn)
{
+ conn->incoming = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) swfdec_rtmp_packet_free);
+ conn->streams = g_hash_table_new (g_direct_hash, g_direct_equal);
+
conn->read_size = SWFDEC_RTMP_BLOCK_SIZE;
conn->write_size = SWFDEC_RTMP_BLOCK_SIZE;
+
+ swfdec_rtmp_register_stream (conn, 0, SWFDEC_RTMP_STREAM (conn));
}
void
@@ -197,3 +238,28 @@ swfdec_rtmp_connection_get_channel (SwfdecRtmpConnection *conn, guint id)
return NULL;
}
+void
+swfdec_rtmp_register_stream (SwfdecRtmpConnection *conn,
+ guint id, SwfdecRtmpStream *stream)
+{
+ g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
+ g_return_if_fail (SWFDEC_IS_RTMP_STREAM (stream));
+
+ if (g_hash_table_lookup (conn->streams, GUINT_TO_POINTER (id))) {
+ SWFDEC_FIXME ("stream %u is already registered, ignoring new request",
+ id);
+ return;
+ }
+
+ g_hash_table_insert (conn->streams, GUINT_TO_POINTER (id), stream);
+}
+
+void
+swfdec_rtmp_unregister_stream (SwfdecRtmpConnection *conn, guint id)
+{
+ g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
+
+ if (!g_hash_table_remove (conn->streams, GUINT_TO_POINTER (id))) {
+ g_assert_not_reached ();
+ }
+}
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index f294417..eb37958 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -56,6 +56,8 @@ struct _SwfdecRtmpConnection {
GList * last_send; /* list entry of last channel sent to */
SwfdecRtmpChannel * handshake; /* channel used for doing initial handshake or NULL */
char * error; /* NULL or debug string for error message */
+ GHashTable * incoming; /* channel id => incoming packets */
+ GHashTable * streams; /* stream id => stream */
guint read_size; /* size of a block of data when reading */
guint write_size; /* size of a block of data when writing */
@@ -85,6 +87,12 @@ void swfdec_rtmp_connection_errorv (SwfdecRtmpConnection * conn,
void swfdec_rtmp_connection_on_status (SwfdecRtmpConnection * conn,
SwfdecAsValue value);
+void swfdec_rtmp_register_stream (SwfdecRtmpConnection * conn,
+ guint id,
+ SwfdecRtmpStream * stream);
+void swfdec_rtmp_unregister_stream (SwfdecRtmpConnection * conn,
+ guint id);
+
#define swfdec_rtmp_connection_get_handshake_channel(conn) ((conn)->handshake)
#define swfdec_rtmp_connection_get_command_channel(conn) (swfdec_rtmp_connection_get_channel (conn, 2))
#define swfdec_rtmp_connection_get_rpc_channel(conn) (swfdec_rtmp_connection_get_channel (conn, 3))
diff --git a/swfdec/swfdec_rtmp_header.c b/swfdec/swfdec_rtmp_header.c
index cb3f6bf..b0836b2 100644
--- a/swfdec/swfdec_rtmp_header.c
+++ b/swfdec/swfdec_rtmp_header.c
@@ -23,6 +23,8 @@
#include "swfdec_rtmp_header.h"
+#include <string.h>
+
gsize
swfdec_rtmp_header_peek_size (guint first_byte)
{
@@ -51,7 +53,7 @@ swfdec_rtmp_header_invalidate (SwfdecRtmpHeader *header)
{
g_return_if_fail (header != NULL);
- header->channel = (guint) -1;
+ memset (header, 0, sizeof (SwfdecRtmpHeader));
}
void
diff --git a/swfdec/swfdec_rtmp_packet.c b/swfdec/swfdec_rtmp_packet.c
index 58a0a9e..ae3d133 100644
--- a/swfdec/swfdec_rtmp_packet.c
+++ b/swfdec/swfdec_rtmp_packet.c
@@ -24,6 +24,12 @@
#include "swfdec_rtmp_packet.h"
SwfdecRtmpPacket *
+swfdec_rtmp_packet_new_empty (void)
+{
+ return g_slice_new0 (SwfdecRtmpPacket);
+}
+
+SwfdecRtmpPacket *
swfdec_rtmp_packet_new (SwfdecRtmpPacketType type, guint timestamp,
SwfdecBuffer *buffer)
{
@@ -31,7 +37,7 @@ swfdec_rtmp_packet_new (SwfdecRtmpPacketType type, guint timestamp,
g_return_val_if_fail (buffer != NULL, NULL);
- packet = g_slice_new0 (SwfdecRtmpPacket);
+ packet = swfdec_rtmp_packet_new_empty ();
packet->header.type = type;
packet->header.timestamp = timestamp;
packet->buffer = swfdec_buffer_ref (buffer);
@@ -44,7 +50,8 @@ swfdec_rtmp_packet_free (SwfdecRtmpPacket *packet)
{
g_return_if_fail (packet != NULL);
- swfdec_buffer_unref (packet->buffer);
+ if (packet->buffer)
+ swfdec_buffer_unref (packet->buffer);
g_slice_free (SwfdecRtmpPacket, packet);
}
diff --git a/swfdec/swfdec_rtmp_packet.h b/swfdec/swfdec_rtmp_packet.h
index 3f83ca7..96482f0 100644
--- a/swfdec/swfdec_rtmp_packet.h
+++ b/swfdec/swfdec_rtmp_packet.h
@@ -33,6 +33,7 @@ struct _SwfdecRtmpPacket {
SwfdecBuffer * buffer; /* contents of packet */
};
+SwfdecRtmpPacket * swfdec_rtmp_packet_new_empty (void);
SwfdecRtmpPacket * swfdec_rtmp_packet_new (SwfdecRtmpPacketType type,
guint timestamp,
SwfdecBuffer * buffer);
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 955eb60..5232f4b 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -23,9 +23,12 @@
#include "swfdec_rtmp_socket.h"
+#include <string.h>
+
#include "swfdec_debug.h"
#include "swfdec_rtmp_handshake_channel.h"
#include "swfdec_player_internal.h"
+#include "swfdec_rtmp_stream.h"
/* socket implementations for swfdec_rtmp_socket_new() */
#include "swfdec_rtmp_socket_rtmp.h"
@@ -147,7 +150,7 @@ void
swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
{
SwfdecRtmpConnection *conn;
- SwfdecRtmpChannel *channel;
+ SwfdecRtmpPacket *packet;
SwfdecRtmpHeader header;
SwfdecBuffer *buffer;
SwfdecBits bits;
@@ -181,43 +184,57 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
break;
swfdec_bits_init (&bits, buffer);
i = swfdec_rtmp_header_peek_channel (&bits);
- channel = swfdec_rtmp_connection_get_channel (conn, i);
- if (channel == NULL) {
- swfdec_rtmp_connection_error (conn,
- "message on unknown channel %u, what now?", i);
- return;
+ packet = g_hash_table_lookup (conn->incoming, GUINT_TO_POINTER (i));
+ if (packet) {
+ swfdec_rtmp_header_copy (&header, &packet->header);
+ } else {
+ swfdec_rtmp_header_invalidate (&header);
}
- if (header_size >= 4 && swfdec_buffer_queue_get_depth (channel->recv_queue)) {
- SWFDEC_ERROR ("not a continuation header, but old command not finished yet, dropping old command");
- swfdec_buffer_queue_flush (channel->recv_queue, swfdec_buffer_queue_get_depth (channel->recv_queue));
- }
- swfdec_rtmp_header_copy (&header, &channel->recv_cache);
swfdec_rtmp_header_read (&header, &bits);
swfdec_buffer_unref (buffer);
/* read the data chunk */
- remaining = header.size - swfdec_buffer_queue_get_depth (channel->recv_queue);
+ remaining = header.size;
+ if (packet && packet->buffer)
+ remaining -= packet->buffer->length;
remaining = MIN (remaining, conn->read_size);
if (header_size + remaining > swfdec_buffer_queue_get_depth (queue))
return;
+
+ if (packet == NULL) {
+ packet = swfdec_rtmp_packet_new_empty ();
+ g_hash_table_insert (conn->incoming, GUINT_TO_POINTER (i), packet);
+ } else if (header_size >= 4 && packet->buffer != NULL) {
+ SWFDEC_ERROR ("not a continuation header, but old command not finished yet, dropping old command");
+ swfdec_buffer_unref (packet->buffer);
+ packet->buffer = NULL;
+ }
+ if (packet->buffer == NULL) {
+ packet->buffer = swfdec_buffer_new (header.size);
+ /* we store the actual size of the buffer in packet->header.size, and
+ * use length to count how much data we already received */
+ packet->buffer->length = 0;
+ }
+ swfdec_rtmp_header_copy (&packet->header, &header);
+
swfdec_buffer_queue_flush (queue, header_size);
buffer = swfdec_buffer_queue_pull (queue, remaining);
g_assert (buffer);
- swfdec_buffer_queue_push (channel->recv_queue, buffer);
- swfdec_rtmp_header_copy (&channel->recv_cache, &header);
-
- /* process the buffer if it's received completely */
- buffer = swfdec_buffer_queue_pull (channel->recv_queue, header.size);
- if (buffer) {
- SwfdecRtmpChannelClass *klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
-
- g_assert (swfdec_buffer_queue_get_depth (channel->recv_queue) == 0);
- if (header.stream != channel->stream_id) {
- SWFDEC_FIXME ("channel has stream id %u, but message has stream id %u, is this bad?",
- channel->stream_id, header.stream);
+ /* we allocate the buffer so it's big enough */
+ memcpy (packet->buffer->data + packet->buffer->length, buffer->data, remaining);
+ packet->buffer->length += remaining;
+ swfdec_buffer_unref (buffer);
+
+ if (packet->buffer->length == header.size) {
+ SwfdecRtmpStream *stream = g_hash_table_lookup (conn->streams, GUINT_TO_POINTER (header.stream));
+
+ if (stream) {
+ swfdec_rtmp_stream_receive (stream, packet);
+ } else {
+ SWFDEC_FIXME ("packet (type %u) for unknown stream %u", header.type, header.stream);
}
- klass->receive (channel, &header, buffer);
- swfdec_buffer_unref (buffer);
+ swfdec_buffer_unref (packet->buffer);
+ packet->buffer = NULL;
}
} while (TRUE);
}
commit c07252c9beb8ef750c3d3ea62882da3a4b26aa90
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 18:17:02 2008 +0100
make SwfdecRtmpPacket take a full header
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index c815809..ea92761 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -135,7 +135,8 @@ swfdec_rtmp_channel_next_buffer (SwfdecRtmpChannel *channel)
buffer = packet->buffer;
bots = swfdec_bots_new ();
header.channel = channel->channel_id;
- header.type = packet->type;
+ header.type = packet->header.type;
+ header.timestamp = packet->header.timestamp;
header.size = buffer->length;
header.stream = channel->stream_id;
diff --git a/swfdec/swfdec_rtmp_packet.c b/swfdec/swfdec_rtmp_packet.c
index 09aeae9..58a0a9e 100644
--- a/swfdec/swfdec_rtmp_packet.c
+++ b/swfdec/swfdec_rtmp_packet.c
@@ -32,8 +32,8 @@ swfdec_rtmp_packet_new (SwfdecRtmpPacketType type, guint timestamp,
g_return_val_if_fail (buffer != NULL, NULL);
packet = g_slice_new0 (SwfdecRtmpPacket);
- packet->type = type;
- packet->timestamp = timestamp;
+ packet->header.type = type;
+ packet->header.timestamp = timestamp;
packet->buffer = swfdec_buffer_ref (buffer);
return packet;
diff --git a/swfdec/swfdec_rtmp_packet.h b/swfdec/swfdec_rtmp_packet.h
index aa1ce19..3f83ca7 100644
--- a/swfdec/swfdec_rtmp_packet.h
+++ b/swfdec/swfdec_rtmp_packet.h
@@ -29,8 +29,7 @@ G_BEGIN_DECLS
typedef struct _SwfdecRtmpPacket SwfdecRtmpPacket;
struct _SwfdecRtmpPacket {
- SwfdecRtmpPacketType type; /* type of packet */
- guint timestamp; /* timestamp associated with this packet */
+ SwfdecRtmpHeader header; /* header to use in packet */
SwfdecBuffer * buffer; /* contents of packet */
};
commit 56248d17a401912887357ed7bb375b77560f5148
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 18:12:02 2008 +0100
improve debug message
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index d056eb5..241dff8 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -191,7 +191,8 @@ swfdec_rtmp_rpc_channel_receive (SwfdecRtmpChannel *channel,
}
break;
default:
- SWFDEC_FIXME ("what to do with header type %u?", header->type);
+ SWFDEC_FIXME ("channel %u: what to do with header type %u?",
+ channel->channel_id, header->type);
break;
}
swfdec_sandbox_unuse (channel->conn->sandbox);
commit 728284a572ad4552ac154bfc1a79ad6aac9a0f81
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 15:56:23 2008 +0100
handle chunk size message
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 8842040..300842b 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -79,8 +79,10 @@ swfdec_rtmp_connection_class_init (SwfdecRtmpConnectionClass *klass)
}
static void
-swfdec_rtmp_connection_init (SwfdecRtmpConnection *rtmp_connection)
+swfdec_rtmp_connection_init (SwfdecRtmpConnection *conn)
{
+ conn->read_size = SWFDEC_RTMP_BLOCK_SIZE;
+ conn->write_size = SWFDEC_RTMP_BLOCK_SIZE;
}
void
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index cee8aaf..f294417 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -56,6 +56,9 @@ struct _SwfdecRtmpConnection {
GList * last_send; /* list entry of last channel sent to */
SwfdecRtmpChannel * handshake; /* channel used for doing initial handshake or NULL */
char * error; /* NULL or debug string for error message */
+
+ guint read_size; /* size of a block of data when reading */
+ guint write_size; /* size of a block of data when writing */
};
struct _SwfdecRtmpConnectionClass {
diff --git a/swfdec/swfdec_rtmp_control_channel.c b/swfdec/swfdec_rtmp_control_channel.c
index 03a7274..013862a 100644
--- a/swfdec/swfdec_rtmp_control_channel.c
+++ b/swfdec/swfdec_rtmp_control_channel.c
@@ -44,6 +44,19 @@ swfdec_rtmp_control_channel_push (SwfdecRtmpControlChannel *control,
}
static void
+swfdec_rtmp_control_channel_handle_chunk_size (SwfdecRtmpChannel *channel, SwfdecBuffer *buffer)
+{
+ SwfdecBits bits;
+
+ swfdec_bits_init (&bits, buffer);
+ channel->conn->read_size = swfdec_bits_get_bu32 (&bits);
+ SWFDEC_INFO ("setting read chunk size to %u", channel->conn->read_size);
+ if (swfdec_bits_left (&bits)) {
+ SWFDEC_FIXME ("%u bytes left after chunk size", swfdec_bits_left (&bits) / 8);
+ }
+}
+
+static void
swfdec_rtmp_control_channel_handle_ping (SwfdecRtmpChannel *channel, SwfdecBuffer *buffer)
{
SwfdecBits bits;
@@ -107,6 +120,9 @@ swfdec_rtmp_control_channel_receive (SwfdecRtmpChannel *channel,
const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
{
switch ((guint) header->type) {
+ case SWFDEC_RTMP_PACKET_SIZE:
+ swfdec_rtmp_control_channel_handle_chunk_size (channel, buffer);
+ break;
case SWFDEC_RTMP_PACKET_PING:
swfdec_rtmp_control_channel_handle_ping (channel, buffer);
break;
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 29acf92..955eb60 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -197,7 +197,7 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
/* read the data chunk */
remaining = header.size - swfdec_buffer_queue_get_depth (channel->recv_queue);
- remaining = MIN (remaining, SWFDEC_RTMP_BLOCK_SIZE);
+ remaining = MIN (remaining, conn->read_size);
if (header_size + remaining > swfdec_buffer_queue_get_depth (queue))
return;
swfdec_buffer_queue_flush (queue, header_size);
commit 67ef5217b2fd682734526576ae0ceada7161723f
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 15:49:22 2008 +0100
make NetStream RPC actually work
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index b0b37cd..163a9e8 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -158,6 +158,8 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream->conn = conn;
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
stream->rpc_channel = swfdec_rtmp_rpc_channel_new (conn);
+ swfdec_rtmp_rpc_channel_set_target (SWFDEC_RTMP_RPC_CHANNEL (stream->rpc_channel),
+ swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (stream)));
stream->video_channel = swfdec_rtmp_video_channel_new (conn);
/* FIXME: new class for audio plz */
stream->audio_channel = swfdec_rtmp_rpc_channel_new (conn);
@@ -181,8 +183,8 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
stream->stream_id = stream_id;
channel_id = 4 + ((stream_id - 1) * 5);
swfdec_rtmp_channel_register (stream->rpc_channel, channel_id, stream_id);
- swfdec_rtmp_channel_register (stream->video_channel, channel_id, stream_id + 1);
- swfdec_rtmp_channel_register (stream->audio_channel, channel_id, stream_id + 2);
+ swfdec_rtmp_channel_register (stream->video_channel, channel_id + 1, stream_id);
+ swfdec_rtmp_channel_register (stream->audio_channel, channel_id + 2, stream_id);
}
SWFDEC_AS_NATIVE (2101, 202, swfdec_net_stream_send_connection)
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 7adbf26..c815809 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -180,6 +180,8 @@ swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel,
SWFDEC_FIXME ("figure out how huge ids (like %u) are handled. Channel registration failed", channel_id);
return;
}
+ SWFDEC_DEBUG ("registering %s as channel %u for stream %u", G_OBJECT_TYPE_NAME (channel),
+ channel_id, stream_id);
conn = channel->conn;
conn->channels = g_list_insert_sorted (conn->channels, channel,
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index 2a29842..d056eb5 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -132,6 +132,7 @@ swfdec_rtmp_rpc_channel_receive_call (SwfdecRtmpChannel *channel,
SwfdecAmfContext *cx, SwfdecAsValue val, SwfdecBits *bits)
{
SwfdecAsContext *context = swfdec_gc_object_get_context (channel->conn);
+ SwfdecRtmpRpcChannel *rpc = SWFDEC_RTMP_RPC_CHANNEL (channel);
const char *name;
guint id, i;
SwfdecAsValue *args;
@@ -153,13 +154,12 @@ swfdec_rtmp_rpc_channel_receive_call (SwfdecRtmpChannel *channel,
return;
}
}
- swfdec_as_relay_call (SWFDEC_AS_RELAY (channel->conn), name,
- i, args, &val);
+ swfdec_as_object_call (rpc->target, name, i, args, &val);
g_free (args);
/* send reply */
if (id) {
- swfdec_rtmp_rpc_channel_do_send (SWFDEC_RTMP_RPC_CHANNEL (channel),
+ swfdec_rtmp_rpc_channel_do_send (rpc,
SWFDEC_AS_VALUE_FROM_STRING (SWFDEC_AS_STR__result), id, val, 0, NULL);
}
}
@@ -173,9 +173,6 @@ swfdec_rtmp_rpc_channel_receive (SwfdecRtmpChannel *channel,
SwfdecAsValue val;
SwfdecBits bits;
- if (header->stream != 0) {
- SWFDEC_FIXME ("not stream 0, but stream %u here?!", header->stream);
- }
context = swfdec_gc_object_get_context (channel->conn);
cx = swfdec_amf_context_new (context);
swfdec_sandbox_use (channel->conn->sandbox);
@@ -218,6 +215,8 @@ swfdec_rtmp_rpc_channel_mark (SwfdecRtmpChannel *channel)
g_hash_table_iter_next (&iter, NULL, &value);) {
swfdec_as_object_mark (value);
}
+
+ swfdec_as_object_mark (rpc->target);
}
static void
@@ -289,8 +288,21 @@ swfdec_rtmp_rpc_channel_send (SwfdecRtmpRpcChannel *rpc,
SwfdecRtmpChannel *
swfdec_rtmp_rpc_channel_new (SwfdecRtmpConnection *conn)
{
+ SwfdecRtmpRpcChannel *rpc;
g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
- return g_object_new (SWFDEC_TYPE_RTMP_RPC_CHANNEL, "connection", conn, NULL);
+ rpc = g_object_new (SWFDEC_TYPE_RTMP_RPC_CHANNEL, "connection", conn, NULL);
+ rpc->target = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (conn));
+
+ return SWFDEC_RTMP_CHANNEL (rpc);
+}
+
+void
+swfdec_rtmp_rpc_channel_set_target (SwfdecRtmpRpcChannel *rpc, SwfdecAsObject *object)
+{
+ g_return_if_fail (SWFDEC_IS_RTMP_RPC_CHANNEL (rpc));
+ g_return_if_fail (object != NULL);
+
+ rpc->target = object;
}
diff --git a/swfdec/swfdec_rtmp_rpc_channel.h b/swfdec/swfdec_rtmp_rpc_channel.h
index 316b9a7..b4b69b1 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.h
+++ b/swfdec/swfdec_rtmp_rpc_channel.h
@@ -39,6 +39,7 @@ typedef struct _SwfdecRtmpRpcChannelClass SwfdecRtmpRpcChannelClass;
struct _SwfdecRtmpRpcChannel {
SwfdecRtmpChannel channel;
+ SwfdecAsObject * target; /* object to call received calls on */
guint id; /* last id used for RPC call */
GHashTable * pending; /* int => SwfdecAsObject mapping of calls having pending replies */
GQueue * packets; /* outstanding packets */
@@ -61,6 +62,9 @@ void swfdec_rtmp_rpc_channel_send (SwfdecRtmpRpcChannel * rpc,
guint argc,
const SwfdecAsValue * argv);
+void swfdec_rtmp_rpc_channel_set_target (SwfdecRtmpRpcChannel * rpc,
+ SwfdecAsObject * object);
+
G_END_DECLS
#endif
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 6ba9028..29acf92 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -212,6 +212,10 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
SwfdecRtmpChannelClass *klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
g_assert (swfdec_buffer_queue_get_depth (channel->recv_queue) == 0);
+ if (header.stream != channel->stream_id) {
+ SWFDEC_FIXME ("channel has stream id %u, but message has stream id %u, is this bad?",
+ channel->stream_id, header.stream);
+ }
klass->receive (channel, &header, buffer);
swfdec_buffer_unref (buffer);
}
commit f4fed1e8c62da3a03c04131b607699e520a7fcea
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 14:04:24 2008 +0100
rewrite sending of packets to use SwfdecRtmpPacket
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 7e640c9..7adbf26 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -109,34 +109,52 @@ swfdec_rtmp_channel_init (SwfdecRtmpChannel *channel)
channel->send_queue = swfdec_buffer_queue_new ();
}
-void
-swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
- const SwfdecRtmpHeader *header, SwfdecBuffer *data)
+SwfdecBuffer *
+swfdec_rtmp_channel_next_buffer (SwfdecRtmpChannel *channel)
{
+ SwfdecRtmpChannelClass *klass;
+ SwfdecRtmpPacket *packet;
+ SwfdecRtmpHeader header;
+ SwfdecBuffer *buffer;
SwfdecBots *bots;
- gsize i;
+ guint i;
- g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
- g_return_if_fail (header != NULL);
- g_return_if_fail (data != NULL);
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel), NULL);
+ g_return_val_if_fail (swfdec_rtmp_channel_is_registered (channel), NULL);
+
+ buffer = swfdec_buffer_queue_pull_buffer (channel->send_queue);
+ if (buffer)
+ return buffer;
+ klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
+ swfdec_rtmp_header_copy (&header, &channel->send_cache);
+ packet = klass->send (channel);
+ if (packet == NULL)
+ return NULL;
+
+ buffer = packet->buffer;
bots = swfdec_bots_new ();
- swfdec_rtmp_header_write (header, bots,
- swfdec_rtmp_header_diff (header, &channel->send_cache));
- swfdec_rtmp_header_copy (&channel->send_cache, header);
+ header.channel = channel->channel_id;
+ header.type = packet->type;
+ header.size = buffer->length;
+ header.stream = channel->stream_id;
+
+ swfdec_rtmp_header_write (&header, bots,
+ swfdec_rtmp_header_diff (&header, &channel->send_cache));
+ swfdec_rtmp_header_copy (&channel->send_cache, &header);
- for (i = 0; i < data->length; i += SWFDEC_RTMP_BLOCK_SIZE) {
+ for (i = 0; i < buffer->length; i += SWFDEC_RTMP_BLOCK_SIZE) {
if (i != 0) {
/* write a continuation header */
bots = swfdec_bots_new ();
- swfdec_rtmp_header_write (header, bots, SWFDEC_RTMP_HEADER_1_BYTE);
+ swfdec_rtmp_header_write (&header, bots, SWFDEC_RTMP_HEADER_1_BYTE);
}
- swfdec_bots_put_data (bots, data->data + i, MIN (SWFDEC_RTMP_BLOCK_SIZE, data->length - i));
+ swfdec_bots_put_data (bots, buffer->data + i, MIN (SWFDEC_RTMP_BLOCK_SIZE, buffer->length - i));
swfdec_buffer_queue_push (channel->send_queue, swfdec_bots_close (bots));
}
+ swfdec_rtmp_packet_free (packet);
- if (swfdec_rtmp_channel_is_registered (channel))
- swfdec_rtmp_socket_send (channel->conn->socket);
+ return swfdec_buffer_queue_pull_buffer (channel->send_queue);
}
static int
@@ -170,8 +188,7 @@ swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel,
channel->stream_id = stream_id;
g_object_ref (channel);
- if (swfdec_buffer_queue_get_depth (channel->send_queue) > 0)
- swfdec_rtmp_socket_send (channel->conn->socket);
+ swfdec_rtmp_socket_send (channel->conn->socket);
}
void
diff --git a/swfdec/swfdec_rtmp_channel.h b/swfdec/swfdec_rtmp_channel.h
index 6e1686b..4fa985a 100644
--- a/swfdec/swfdec_rtmp_channel.h
+++ b/swfdec/swfdec_rtmp_channel.h
@@ -22,6 +22,7 @@
#include <swfdec/swfdec_rtmp_connection.h>
#include <swfdec/swfdec_rtmp_header.h>
+#include <swfdec/swfdec_rtmp_packet.h>
G_BEGIN_DECLS
@@ -56,16 +57,19 @@ struct _SwfdecRtmpChannelClass {
void (* receive) (SwfdecRtmpChannel * channel,
const SwfdecRtmpHeader *header,
SwfdecBuffer * buffer);
+ SwfdecRtmpPacket * (* send) (SwfdecRtmpChannel * channel);
};
GType swfdec_rtmp_channel_get_type (void);
-void swfdec_rtmp_channel_send (SwfdecRtmpChannel * channel,
- const SwfdecRtmpHeader *header,
- SwfdecBuffer * data);
+SwfdecBuffer * swfdec_rtmp_channel_next_buffer (SwfdecRtmpChannel * channel);
#define swfdec_rtmp_channel_get_time(channel, tv) (swfdec_as_context_get_time (swfdec_gc_object_get_context ((channel)->conn), tv))
#define swfdec_rtmp_channel_is_registered(channel) ((channel)->channel_id > 0)
+#define swfdec_rtmp_channel_send(channel) G_STMT_START{\
+ if (swfdec_rtmp_channel_is_registered(channel)) \
+ swfdec_rtmp_socket_send (channel->conn->socket); \
+}G_STMT_END
void swfdec_rtmp_channel_register (SwfdecRtmpChannel * channel,
guint channel_id,
guint stream_id);
diff --git a/swfdec/swfdec_rtmp_control_channel.c b/swfdec/swfdec_rtmp_control_channel.c
index 473eede..03a7274 100644
--- a/swfdec/swfdec_rtmp_control_channel.c
+++ b/swfdec/swfdec_rtmp_control_channel.c
@@ -32,6 +32,18 @@
G_DEFINE_TYPE (SwfdecRtmpControlChannel, swfdec_rtmp_control_channel, SWFDEC_TYPE_RTMP_CHANNEL)
static void
+swfdec_rtmp_control_channel_push (SwfdecRtmpControlChannel *control,
+ SwfdecRtmpPacket *packet)
+{
+ gboolean empty = g_queue_is_empty (control->send_packets);
+
+ g_queue_push_tail (control->send_packets, packet);
+
+ if (empty)
+ swfdec_rtmp_channel_send (SWFDEC_RTMP_CHANNEL (control));
+}
+
+static void
swfdec_rtmp_control_channel_handle_ping (SwfdecRtmpChannel *channel, SwfdecBuffer *buffer)
{
SwfdecBits bits;
@@ -51,7 +63,7 @@ swfdec_rtmp_control_channel_handle_server_bandwidth (SwfdecRtmpChannel *channel,
SwfdecBits bits;
SwfdecBots *bots;
guint new_bandwidth;
- SwfdecRtmpHeader header;
+ SwfdecRtmpPacket *packet;
GTimeVal tv;
long diff;
@@ -65,18 +77,15 @@ swfdec_rtmp_control_channel_handle_server_bandwidth (SwfdecRtmpChannel *channel,
bots = swfdec_bots_new ();
swfdec_bots_put_bu32 (bots, new_bandwidth);
buffer = swfdec_bots_close (bots);
- header.channel = channel->channel_id;
/* send diff between the timestamp that the server sent and our current time.
* FIXME: Is that correct? */
swfdec_rtmp_channel_get_time (channel, &tv);
diff = swfdec_time_val_diff (&channel->timestamp, &tv);
- header.timestamp = org_header->timestamp - diff;
- header.size = buffer->length;
- header.type = SWFDEC_RTMP_PACKET_SERVER_BANDWIDTH;
- header.stream = 0;
-
- swfdec_rtmp_channel_send (channel, &header, buffer);
+ packet = swfdec_rtmp_packet_new (SWFDEC_RTMP_PACKET_SERVER_BANDWIDTH,
+ org_header->timestamp - diff, buffer);
swfdec_buffer_unref (buffer);
+
+ swfdec_rtmp_control_channel_push (control, packet);
}
static void
@@ -113,10 +122,24 @@ swfdec_rtmp_control_channel_receive (SwfdecRtmpChannel *channel,
}
}
+static SwfdecRtmpPacket *
+swfdec_rtmp_control_channel_send (SwfdecRtmpChannel *channel)
+{
+ SwfdecRtmpControlChannel *control = SWFDEC_RTMP_CONTROL_CHANNEL (channel);
+
+ return g_queue_pop_head (control->send_packets);
+}
+
static void
swfdec_rtmp_control_channel_dispose (GObject *object)
{
- //SwfdecRtmpControlChannel *conn = SWFDEC_RTMP_CONTROL_CHANNEL (object);
+ SwfdecRtmpControlChannel *control = SWFDEC_RTMP_CONTROL_CHANNEL (object);
+
+ if (control->send_packets) {
+ g_queue_foreach (control->send_packets, (GFunc) swfdec_rtmp_packet_free, NULL);
+ g_queue_free (control->send_packets);
+ control->send_packets = NULL;
+ }
G_OBJECT_CLASS (swfdec_rtmp_control_channel_parent_class)->dispose (object);
}
@@ -130,11 +153,13 @@ swfdec_rtmp_control_channel_class_init (SwfdecRtmpControlChannelClass *klass)
object_class->dispose = swfdec_rtmp_control_channel_dispose;
channel_class->receive = swfdec_rtmp_control_channel_receive;
+ channel_class->send = swfdec_rtmp_control_channel_send;
}
static void
-swfdec_rtmp_control_channel_init (SwfdecRtmpControlChannel *command)
+swfdec_rtmp_control_channel_init (SwfdecRtmpControlChannel *control)
{
+ control->send_packets = g_queue_new ();
}
SwfdecRtmpChannel *
diff --git a/swfdec/swfdec_rtmp_control_channel.h b/swfdec/swfdec_rtmp_control_channel.h
index 95baf4c..5a56bc6 100644
--- a/swfdec/swfdec_rtmp_control_channel.h
+++ b/swfdec/swfdec_rtmp_control_channel.h
@@ -38,6 +38,7 @@ typedef struct _SwfdecRtmpControlChannelClass SwfdecRtmpControlChannelClass;
struct _SwfdecRtmpControlChannel {
SwfdecRtmpChannel channel;
+ GQueue * send_packets; /* packets that still need to be sent */
guint server_bandwidth;
guint client_bandwidth;
};
diff --git a/swfdec/swfdec_rtmp_handshake_channel.c b/swfdec/swfdec_rtmp_handshake_channel.c
index 0a50d64..ec39e23 100644
--- a/swfdec/swfdec_rtmp_handshake_channel.c
+++ b/swfdec/swfdec_rtmp_handshake_channel.c
@@ -130,7 +130,6 @@ swfdec_rtmp_handshake_channel_push_connect (SwfdecRtmpHandshakeChannel *shake)
swfdec_rtmp_rpc_channel_send_connect (SWFDEC_RTMP_RPC_CHANNEL (
swfdec_rtmp_connection_get_rpc_channel (conn)), SWFDEC_AS_VALUE_FROM_OBJECT (o));
- swfdec_rtmp_header_invalidate (&swfdec_rtmp_connection_get_rpc_channel (conn)->send_cache);
}
void
@@ -161,21 +160,14 @@ swfdec_rtmp_handshake_channel_redirect_connect (SwfdecRtmpHandshakeChannel *shak
{
SwfdecRtmpConnection *conn = SWFDEC_RTMP_CHANNEL (shake)->conn;
SwfdecRtmpChannel *rpc = swfdec_rtmp_connection_get_rpc_channel (conn);
- SwfdecRtmpHeader header;
SwfdecBuffer *buffer;
- SwfdecBits bits;
- buffer = swfdec_buffer_queue_pull_buffer (rpc->send_queue);
- swfdec_bits_init (&bits, buffer);
- swfdec_rtmp_header_read (&header, &bits);
- header.size -= (buffer->length - 12);
+ buffer = swfdec_rtmp_channel_next_buffer (rpc);
swfdec_buffer_queue_push (SWFDEC_RTMP_CHANNEL (shake)->send_queue, buffer);
- while (header.size > 0) {
- buffer = swfdec_buffer_queue_pull_buffer (rpc->send_queue);
- g_assert (header.size >= buffer->length - 1);
- header.size -= buffer->length - 1;
+ while ((buffer = swfdec_buffer_queue_pull_buffer (rpc->send_queue))) {
swfdec_buffer_queue_push (SWFDEC_RTMP_CHANNEL (shake)->send_queue, buffer);
}
+ swfdec_rtmp_header_invalidate (&rpc->send_cache);
}
gboolean
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index 58c7338..2a29842 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -53,10 +53,11 @@ swfdec_rtmp_rpc_channel_do_send (SwfdecRtmpRpcChannel *rpc, SwfdecAsValue name,
{
SwfdecRtmpChannel *channel;
SwfdecAsContext *context;
- SwfdecRtmpHeader header;
+ SwfdecRtmpPacket *packet;
SwfdecAmfContext *cx;
SwfdecBuffer *buffer;
SwfdecBots *bots;
+ gboolean empty;
guint i;
channel = SWFDEC_RTMP_CHANNEL (rpc);
@@ -74,13 +75,12 @@ swfdec_rtmp_rpc_channel_do_send (SwfdecRtmpRpcChannel *rpc, SwfdecAsValue name,
buffer = swfdec_bots_close (bots);
swfdec_amf_context_free (cx);
- header.channel = channel->channel_id;
- header.timestamp = swfdec_rtmp_rpc_channel_update_last_send (channel);
- header.size = buffer->length;
- header.type = SWFDEC_RTMP_PACKET_INVOKE;
- header.stream = 0;
-
- swfdec_rtmp_channel_send (channel, &header, buffer);
+ packet = swfdec_rtmp_packet_new (SWFDEC_RTMP_PACKET_INVOKE,
+ swfdec_rtmp_rpc_channel_update_last_send (channel), buffer);
+ empty = g_queue_is_empty (rpc->packets);
+ g_queue_push_tail (rpc->packets, packet);
+ if (empty)
+ swfdec_rtmp_channel_send (channel);
}
static void
@@ -201,6 +201,12 @@ swfdec_rtmp_rpc_channel_receive (SwfdecRtmpChannel *channel,
swfdec_amf_context_free (cx);
}
+static SwfdecRtmpPacket *
+swfdec_rtmp_rpc_channel_send_vfunc (SwfdecRtmpChannel *channel)
+{
+ return g_queue_pop_head (SWFDEC_RTMP_RPC_CHANNEL (channel)->packets);
+}
+
static void
swfdec_rtmp_rpc_channel_mark (SwfdecRtmpChannel *channel)
{
@@ -223,6 +229,12 @@ swfdec_rtmp_rpc_channel_dispose (GObject *object)
g_hash_table_destroy (rpc->pending);
rpc->pending = NULL;
}
+ if (rpc->packets) {
+ g_queue_foreach (rpc->packets, (GFunc) swfdec_rtmp_packet_free, NULL);
+ g_queue_free (rpc->packets);
+ rpc->packets = NULL;
+ }
+
G_OBJECT_CLASS (swfdec_rtmp_rpc_channel_parent_class)->dispose (object);
}
@@ -237,12 +249,14 @@ swfdec_rtmp_rpc_channel_class_init (SwfdecRtmpRpcChannelClass *klass)
channel_class->mark = swfdec_rtmp_rpc_channel_mark;
channel_class->receive = swfdec_rtmp_rpc_channel_receive;
+ channel_class->send = swfdec_rtmp_rpc_channel_send_vfunc;
}
static void
swfdec_rtmp_rpc_channel_init (SwfdecRtmpRpcChannel *rpc)
{
rpc->pending = g_hash_table_new (g_direct_hash, g_direct_equal);
+ rpc->packets = g_queue_new ();
}
void
diff --git a/swfdec/swfdec_rtmp_rpc_channel.h b/swfdec/swfdec_rtmp_rpc_channel.h
index cdced09..316b9a7 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.h
+++ b/swfdec/swfdec_rtmp_rpc_channel.h
@@ -41,6 +41,7 @@ struct _SwfdecRtmpRpcChannel {
guint id; /* last id used for RPC call */
GHashTable * pending; /* int => SwfdecAsObject mapping of calls having pending replies */
+ GQueue * packets; /* outstanding packets */
GTimeVal last_send; /* time the last call was sent */
};
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 9e05577..6ba9028 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -134,8 +134,8 @@ swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
do {
walk = walk->next ? walk->next : conn->channels;
channel = walk->data;
- buffer = swfdec_buffer_queue_pull_buffer (channel->send_queue);
- if (buffer) {
+ buffer = swfdec_rtmp_channel_next_buffer (channel);
+ if (buffer != NULL) {
conn->last_send = walk;
return buffer;
}
diff --git a/swfdec/swfdec_rtmp_video_channel.c b/swfdec/swfdec_rtmp_video_channel.c
index 5a73e5d..1f8697f 100644
--- a/swfdec/swfdec_rtmp_video_channel.c
+++ b/swfdec/swfdec_rtmp_video_channel.c
@@ -59,6 +59,12 @@ swfdec_rtmp_video_channel_receive (SwfdecRtmpChannel *channel,
{
}
+static SwfdecRtmpPacket *
+swfdec_rtmp_video_channel_send (SwfdecRtmpChannel *channel)
+{
+ return NULL;
+}
+
static void
swfdec_rtmp_video_channel_dispose (GObject *object)
{
@@ -76,6 +82,7 @@ swfdec_rtmp_video_channel_class_init (SwfdecRtmpVideoChannelClass *klass)
object_class->dispose = swfdec_rtmp_video_channel_dispose;
channel_class->receive = swfdec_rtmp_video_channel_receive;
+ channel_class->send = swfdec_rtmp_video_channel_send;
}
static void
commit 5c7d140d5421c80616937bec6bf4e47302c84b37
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 11:46:54 2008 +0100
require stream id plus channel id when registering
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 469539e..b0b37cd 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -170,7 +170,7 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
{
SwfdecNetStream *stream;
SwfdecAsObject *o;
- guint stream_id;
+ guint stream_id, channel_id;
SWFDEC_AS_CHECK (0, NULL, "oi", &o, &stream_id);
@@ -179,10 +179,10 @@ swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
stream = SWFDEC_NET_STREAM (o->relay);
stream->stream_id = stream_id;
- stream_id = 4 + ((stream_id - 1 % 12) * 5);
- swfdec_rtmp_channel_register (stream->rpc_channel, stream_id);
- swfdec_rtmp_channel_register (stream->video_channel, stream_id + 1);
- swfdec_rtmp_channel_register (stream->audio_channel, stream_id + 2);
+ channel_id = 4 + ((stream_id - 1) * 5);
+ swfdec_rtmp_channel_register (stream->rpc_channel, channel_id, stream_id);
+ swfdec_rtmp_channel_register (stream->video_channel, channel_id, stream_id + 1);
+ swfdec_rtmp_channel_register (stream->audio_channel, channel_id, stream_id + 2);
}
SWFDEC_AS_NATIVE (2101, 202, swfdec_net_stream_send_connection)
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index b667d79..7e640c9 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -145,27 +145,29 @@ swfdec_rtmp_channel_compare (gconstpointer a, gconstpointer b)
SwfdecRtmpChannel *ca = (SwfdecRtmpChannel *) a;
SwfdecRtmpChannel *cb = (SwfdecRtmpChannel *) b;
- return cb->id - ca->id;
+ return cb->channel_id - ca->channel_id;
}
void
-swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel, guint id)
+swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel,
+ guint channel_id, guint stream_id)
{
SwfdecRtmpConnection *conn;
g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
g_return_if_fail (!swfdec_rtmp_channel_is_registered (channel));
- g_return_if_fail (id > 1);
+ g_return_if_fail (channel_id > 1);
- if (id >= 65536 + 64) {
- SWFDEC_FIXME ("figure out how huge ids (like %u) are handled. Channel registration failed", id);
+ if (channel_id >= 65536 + 64) {
+ SWFDEC_FIXME ("figure out how huge ids (like %u) are handled. Channel registration failed", channel_id);
return;
}
conn = channel->conn;
conn->channels = g_list_insert_sorted (conn->channels, channel,
swfdec_rtmp_channel_compare);
- channel->id = id;
+ channel->channel_id = channel_id;
+ channel->stream_id = stream_id;
g_object_ref (channel);
if (swfdec_buffer_queue_get_depth (channel->send_queue) > 0)
@@ -185,7 +187,8 @@ swfdec_rtmp_channel_unregister (SwfdecRtmpChannel *channel)
channel->conn->last_send->next : channel->conn->last_send->prev;
}
channel->conn->channels = g_list_remove (channel->conn->channels, channel);
- channel->id = 0;
+ channel->channel_id = 0;
+ channel->stream_id = 0;
g_object_unref (channel);
}
diff --git a/swfdec/swfdec_rtmp_channel.h b/swfdec/swfdec_rtmp_channel.h
index d7b9932..6e1686b 100644
--- a/swfdec/swfdec_rtmp_channel.h
+++ b/swfdec/swfdec_rtmp_channel.h
@@ -39,7 +39,8 @@ struct _SwfdecRtmpChannel {
GObject object;
SwfdecRtmpConnection * conn; /* Connection this channel belongs to */
- guint id; /* id inside connection or 0 if no connection */
+ guint channel_id; /* channel id inside connection or 0 if no connection */
+ guint stream_id; /* stream id inside connection */
GTimeVal timestamp; /* timestamp for various uses - set when constructing */
SwfdecRtmpHeader recv_cache; /* cached header info for receiving data */
@@ -64,9 +65,10 @@ void swfdec_rtmp_channel_send (SwfdecRtmpChannel * channel,
SwfdecBuffer * data);
#define swfdec_rtmp_channel_get_time(channel, tv) (swfdec_as_context_get_time (swfdec_gc_object_get_context ((channel)->conn), tv))
-#define swfdec_rtmp_channel_is_registered(channel) ((channel)->id > 0)
+#define swfdec_rtmp_channel_is_registered(channel) ((channel)->channel_id > 0)
void swfdec_rtmp_channel_register (SwfdecRtmpChannel * channel,
- guint id);
+ guint channel_id,
+ guint stream_id);
void swfdec_rtmp_channel_unregister (SwfdecRtmpChannel * channel);
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index f028ca8..8842040 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -104,10 +104,10 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
conn->handshake = swfdec_rtmp_handshake_channel_new (conn);
channel = swfdec_rtmp_control_channel_new (conn);
- swfdec_rtmp_channel_register (channel, 2);
+ swfdec_rtmp_channel_register (channel, 2, 0);
g_object_unref (channel);
channel = swfdec_rtmp_rpc_channel_new (conn);
- swfdec_rtmp_channel_register (channel, 3);
+ swfdec_rtmp_channel_register (channel, 3, 0);
g_object_unref (channel);
conn->last_send = conn->channels;
@@ -185,9 +185,9 @@ swfdec_rtmp_connection_get_channel (SwfdecRtmpConnection *conn, guint id)
for (walk = conn->channels; walk; walk = walk->next) {
channel = walk->data;
- if (channel->id < id)
+ if (channel->channel_id < id)
continue;
- if (channel->id == id)
+ if (channel->channel_id == id)
return channel;
return NULL;
}
diff --git a/swfdec/swfdec_rtmp_control_channel.c b/swfdec/swfdec_rtmp_control_channel.c
index a7a8096..473eede 100644
--- a/swfdec/swfdec_rtmp_control_channel.c
+++ b/swfdec/swfdec_rtmp_control_channel.c
@@ -65,7 +65,7 @@ swfdec_rtmp_control_channel_handle_server_bandwidth (SwfdecRtmpChannel *channel,
bots = swfdec_bots_new ();
swfdec_bots_put_bu32 (bots, new_bandwidth);
buffer = swfdec_bots_close (bots);
- header.channel = channel->id;
+ header.channel = channel->channel_id;
/* send diff between the timestamp that the server sent and our current time.
* FIXME: Is that correct? */
swfdec_rtmp_channel_get_time (channel, &tv);
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index 0fd809d..58c7338 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -74,7 +74,7 @@ swfdec_rtmp_rpc_channel_do_send (SwfdecRtmpRpcChannel *rpc, SwfdecAsValue name,
buffer = swfdec_bots_close (bots);
swfdec_amf_context_free (cx);
- header.channel = channel->id;
+ header.channel = channel->channel_id;
header.timestamp = swfdec_rtmp_rpc_channel_update_last_send (channel);
header.size = buffer->length;
header.type = SWFDEC_RTMP_PACKET_INVOKE;
commit 7bf845395a83875164e92294aa380676215378f9
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Dec 8 11:37:57 2008 +0100
add a SwfdecRtmpPacket type in preparation for further changes
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 84e0026..5a0e33b 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -136,6 +136,7 @@ libswfdec_source_files = \
swfdec_rtmp_connection.c \
swfdec_rtmp_handshake_channel.c \
swfdec_rtmp_header.c \
+ swfdec_rtmp_packet.c \
swfdec_rtmp_rpc_channel.c \
swfdec_rtmp_socket.c \
swfdec_rtmp_socket_rtmp.c \
@@ -335,6 +336,7 @@ noinst_HEADERS = \
swfdec_rtmp_connection.h \
swfdec_rtmp_handshake_channel.h \
swfdec_rtmp_header.h \
+ swfdec_rtmp_packet.h \
swfdec_rtmp_rpc_channel.h \
swfdec_rtmp_socket.h \
swfdec_rtmp_socket_rtmp.h \
diff --git a/swfdec/swfdec_rtmp_packet.c b/swfdec/swfdec_rtmp_packet.c
new file mode 100644
index 0000000..09aeae9
--- /dev/null
+++ b/swfdec/swfdec_rtmp_packet.c
@@ -0,0 +1,51 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_rtmp_packet.h"
+
+SwfdecRtmpPacket *
+swfdec_rtmp_packet_new (SwfdecRtmpPacketType type, guint timestamp,
+ SwfdecBuffer *buffer)
+{
+ SwfdecRtmpPacket *packet;
+
+ g_return_val_if_fail (buffer != NULL, NULL);
+
+ packet = g_slice_new0 (SwfdecRtmpPacket);
+ packet->type = type;
+ packet->timestamp = timestamp;
+ packet->buffer = swfdec_buffer_ref (buffer);
+
+ return packet;
+}
+
+void
+swfdec_rtmp_packet_free (SwfdecRtmpPacket *packet)
+{
+ g_return_if_fail (packet != NULL);
+
+ swfdec_buffer_unref (packet->buffer);
+ g_slice_free (SwfdecRtmpPacket, packet);
+}
+
+
diff --git a/swfdec/swfdec_rtmp_packet.h b/swfdec/swfdec_rtmp_packet.h
new file mode 100644
index 0000000..aa1ce19
--- /dev/null
+++ b/swfdec/swfdec_rtmp_packet.h
@@ -0,0 +1,44 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SWFDEC_RTMP_PACKET_H_
+#define _SWFDEC_RTMP_PACKET_H_
+
+#include <swfdec/swfdec.h>
+#include <swfdec/swfdec_rtmp_header.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecRtmpPacket SwfdecRtmpPacket;
+
+struct _SwfdecRtmpPacket {
+ SwfdecRtmpPacketType type; /* type of packet */
+ guint timestamp; /* timestamp associated with this packet */
+ SwfdecBuffer * buffer; /* contents of packet */
+};
+
+SwfdecRtmpPacket * swfdec_rtmp_packet_new (SwfdecRtmpPacketType type,
+ guint timestamp,
+ SwfdecBuffer * buffer);
+void swfdec_rtmp_packet_free (SwfdecRtmpPacket * packet);
+
+
+G_END_DECLS
+#endif
commit ad0afb3210adcd753093d7ac5b92793d3bdeda69
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 7 22:30:36 2008 +0100
add stubs for a video channel
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 73950b9..84e0026 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -139,6 +139,7 @@ libswfdec_source_files = \
swfdec_rtmp_rpc_channel.c \
swfdec_rtmp_socket.c \
swfdec_rtmp_socket_rtmp.c \
+ swfdec_rtmp_video_channel.c \
swfdec_sandbox.c \
swfdec_script.c \
swfdec_selection.c \
@@ -337,6 +338,7 @@ noinst_HEADERS = \
swfdec_rtmp_rpc_channel.h \
swfdec_rtmp_socket.h \
swfdec_rtmp_socket_rtmp.h \
+ swfdec_rtmp_video_channel.h \
swfdec_sandbox.h \
swfdec_script_internal.h \
swfdec_shape.h \
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 0c0a531..469539e 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -27,6 +27,7 @@
#include "swfdec_as_internal.h"
#include "swfdec_debug.h"
#include "swfdec_rtmp_rpc_channel.h"
+#include "swfdec_rtmp_video_channel.h"
/*** NET STREAM ***/
@@ -157,8 +158,8 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
stream->conn = conn;
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
stream->rpc_channel = swfdec_rtmp_rpc_channel_new (conn);
- /* FIXME: new class for multimedia plz */
- stream->video_channel = swfdec_rtmp_rpc_channel_new (conn);
+ stream->video_channel = swfdec_rtmp_video_channel_new (conn);
+ /* FIXME: new class for audio plz */
stream->audio_channel = swfdec_rtmp_rpc_channel_new (conn);
}
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index 95de86c..0fd809d 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -279,3 +279,4 @@ swfdec_rtmp_rpc_channel_new (SwfdecRtmpConnection *conn)
return g_object_new (SWFDEC_TYPE_RTMP_RPC_CHANNEL, "connection", conn, NULL);
}
+
diff --git a/swfdec/swfdec_rtmp_video_channel.c b/swfdec/swfdec_rtmp_video_channel.c
new file mode 100644
index 0000000..5a73e5d
--- /dev/null
+++ b/swfdec/swfdec_rtmp_video_channel.c
@@ -0,0 +1,92 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_rtmp_video_channel.h"
+
+#include "swfdec_debug.h"
+#include "swfdec_rtmp_socket.h"
+#include "swfdec_video_provider.h"
+
+/*** VIDEO PROVIDER INTERFACE ***/
+
+static cairo_surface_t *
+swfdec_rtmp_video_channel_get_image (SwfdecVideoProvider *prov,
+ SwfdecRenderer *renderer, guint *width, guint *height)
+{
+ return NULL;
+}
+
+static void
+swfdec_rtmp_video_channel_get_size (SwfdecVideoProvider *prov, guint *width, guint *height)
+{
+}
+
+static void
+swfdec_rtmp_video_channel_video_provider_init (SwfdecVideoProviderInterface *iface)
+{
+ iface->get_image = swfdec_rtmp_video_channel_get_image;
+ iface->get_size = swfdec_rtmp_video_channel_get_size;
+}
+
+/*** SwfdecRtmpVideoChannel ***/
+
+G_DEFINE_TYPE_WITH_CODE (SwfdecRtmpVideoChannel, swfdec_rtmp_video_channel, SWFDEC_TYPE_RTMP_CHANNEL,
+ G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_VIDEO_PROVIDER, swfdec_rtmp_video_channel_video_provider_init))
+
+static void
+swfdec_rtmp_video_channel_receive (SwfdecRtmpChannel *channel,
+ const SwfdecRtmpHeader *header, SwfdecBuffer *buffer)
+{
+}
+
+static void
+swfdec_rtmp_video_channel_dispose (GObject *object)
+{
+ //SwfdecRtmpVideoChannel *conn = SWFDEC_RTMP_VIDEO_CHANNEL (object);
+
+ G_OBJECT_CLASS (swfdec_rtmp_video_channel_parent_class)->dispose (object);
+}
+
+static void
+swfdec_rtmp_video_channel_class_init (SwfdecRtmpVideoChannelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ SwfdecRtmpChannelClass *channel_class = SWFDEC_RTMP_CHANNEL_CLASS (klass);
+
+ object_class->dispose = swfdec_rtmp_video_channel_dispose;
+
+ channel_class->receive = swfdec_rtmp_video_channel_receive;
+}
+
+static void
+swfdec_rtmp_video_channel_init (SwfdecRtmpVideoChannel *command)
+{
+}
+
+SwfdecRtmpChannel *
+swfdec_rtmp_video_channel_new (SwfdecRtmpConnection *conn)
+{
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+
+ return g_object_new (SWFDEC_TYPE_RTMP_VIDEO_CHANNEL, "connection", conn, NULL);
+}
diff --git a/swfdec/swfdec_rtmp_video_channel.h b/swfdec/swfdec_rtmp_video_channel.h
new file mode 100644
index 0000000..49f0b15
--- /dev/null
+++ b/swfdec/swfdec_rtmp_video_channel.h
@@ -0,0 +1,52 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SWFDEC_RTMP_VIDEO_CHANNEL_H_
+#define _SWFDEC_RTMP_VIDEO_CHANNEL_H_
+
+#include <swfdec/swfdec_rtmp_channel.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecRtmpVideoChannel SwfdecRtmpVideoChannel;
+typedef struct _SwfdecRtmpVideoChannelClass SwfdecRtmpVideoChannelClass;
+
+#define SWFDEC_TYPE_RTMP_VIDEO_CHANNEL (swfdec_rtmp_video_channel_get_type())
+#define SWFDEC_IS_RTMP_VIDEO_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL))
+#define SWFDEC_IS_RTMP_VIDEO_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL))
+#define SWFDEC_RTMP_VIDEO_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL, SwfdecRtmpVideoChannel))
+#define SWFDEC_RTMP_VIDEO_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL, SwfdecRtmpVideoChannelClass))
+#define SWFDEC_RTMP_VIDEO_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_RTMP_VIDEO_CHANNEL, SwfdecRtmpVideoChannelClass))
+
+struct _SwfdecRtmpVideoChannel {
+ SwfdecRtmpChannel channel;
+};
+
+struct _SwfdecRtmpVideoChannelClass {
+ SwfdecRtmpChannelClass channel_class;
+};
+
+GType swfdec_rtmp_video_channel_get_type (void);
+
+SwfdecRtmpChannel * swfdec_rtmp_video_channel_new (SwfdecRtmpConnection * conn);
+
+
+G_END_DECLS
+#endif
commit 7ad509cb50b45c92135773b2015d8685df5ab81a
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 7 15:48:10 2008 +0100
remove outdated file
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index bb40b2b..73950b9 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -139,7 +139,6 @@ libswfdec_source_files = \
swfdec_rtmp_rpc_channel.c \
swfdec_rtmp_socket.c \
swfdec_rtmp_socket_rtmp.c \
- swfdec_rtmp_stream.c \
swfdec_sandbox.c \
swfdec_script.c \
swfdec_selection.c \
@@ -338,7 +337,6 @@ noinst_HEADERS = \
swfdec_rtmp_rpc_channel.h \
swfdec_rtmp_socket.h \
swfdec_rtmp_socket_rtmp.h \
- swfdec_rtmp_stream.h \
swfdec_sandbox.h \
swfdec_script_internal.h \
swfdec_shape.h \
diff --git a/swfdec/swfdec_rtmp_stream.c b/swfdec/swfdec_rtmp_stream.c
deleted file mode 100644
index beae578..0000000
--- a/swfdec/swfdec_rtmp_stream.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include "swfdec_rtmp_stream.h"
-
-/*** SwfdecRtmpStream ***/
-
-G_DEFINE_TYPE (SwfdecRtmpStream, swfdec_rtmp_stream, G_TYPE_OBJECT)
-
-static void
-swfdec_rtmp_stream_dispose (GObject *object)
-{
- //SwfdecRtmpStream *stream = SWFDEC_RTMP_STREAM (object);
-
- G_OBJECT_CLASS (swfdec_rtmp_stream_parent_class)->dispose (object);
-}
-
-static void
-swfdec_rtmp_stream_class_init (SwfdecRtmpStreamClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = swfdec_rtmp_stream_dispose;
-}
-
-static void
-swfdec_rtmp_stream_init (SwfdecRtmpStream *stream)
-{
-}
-
diff --git a/swfdec/swfdec_rtmp_stream.h b/swfdec/swfdec_rtmp_stream.h
deleted file mode 100644
index fea9435..0000000
--- a/swfdec/swfdec_rtmp_stream.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _SWFDEC_RTMP_STREAM_H_
-#define _SWFDEC_RTMP_STREAM_H_
-
-#include <glib-object.h>
-#include <swfdec/swfdec_rtmp_connection.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _SwfdecRtmpStreamClass SwfdecRtmpStreamClass;
-
-#define SWFDEC_TYPE_RTMP_STREAM (swfdec_rtmp_stream_get_type())
-#define SWFDEC_IS_RTMP_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RTMP_STREAM))
-#define SWFDEC_IS_RTMP_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_RTMP_STREAM))
-#define SWFDEC_RTMP_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RTMP_STREAM, SwfdecRtmpStream))
-#define SWFDEC_RTMP_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_RTMP_STREAM, SwfdecRtmpStreamClass))
-#define SWFDEC_RTMP_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_RTMP_STREAM, SwfdecRtmpStreamClass))
-
-struct _SwfdecRtmpStream {
- GObject object;
-
- SwfdecRtmpConnection *conn; /* the connection that spawned and refs us */
-};
-
-struct _SwfdecRtmpStreamClass {
- GObjectClass object_class;
-};
-
-GType swfdec_rtmp_stream_get_type (void);
-
-
-G_END_DECLS
-#endif
commit 18cc8ecfb182c483c4c39e45c632eed6bd435163
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 7 15:25:05 2008 +0100
hook up NetStream's RPC channel
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index 22859b2..0c0a531 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -26,6 +26,7 @@
#include "swfdec_as_frame_internal.h"
#include "swfdec_as_internal.h"
#include "swfdec_debug.h"
+#include "swfdec_rtmp_rpc_channel.h"
/*** NET STREAM ***/
@@ -45,7 +46,14 @@ swfdec_net_stream_mark (SwfdecGcObject *object)
static void
swfdec_net_stream_dispose (GObject *object)
{
- //SwfdecNetStream *conn = SWFDEC_NET_STREAM (object);
+ SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
+
+ swfdec_rtmp_channel_unregister (stream->rpc_channel);
+ g_object_unref (stream->rpc_channel);
+ swfdec_rtmp_channel_unregister (stream->video_channel);
+ g_object_unref (stream->video_channel);
+ swfdec_rtmp_channel_unregister (stream->audio_channel);
+ g_object_unref (stream->audio_channel);
G_OBJECT_CLASS (swfdec_net_stream_parent_class)->dispose (object);
}
@@ -130,22 +138,28 @@ swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
SwfdecNetStream *stream;
- SwfdecAsObject *o, *conn;
+ SwfdecAsObject *o, *oconn;
+ SwfdecRtmpConnection *conn;
- SWFDEC_AS_CHECK (0, NULL, "oo", &o, &conn);
+ SWFDEC_AS_CHECK (0, NULL, "oo", &o, &oconn);
if (!cx->frame->next || !cx->frame->next->construct)
return;
- if (!SWFDEC_IS_RTMP_CONNECTION (conn->relay))
+ if (!SWFDEC_IS_RTMP_CONNECTION (oconn->relay))
return;
+ conn = SWFDEC_RTMP_CONNECTION (oconn->relay);
if (o->movie) {
SWFDEC_FIXME ("you managed to call SwfdecNetStream's constructor from a movie. Congrats, but what now?");
return;
}
stream = g_object_new (SWFDEC_TYPE_NET_STREAM, "context", cx, NULL);
- stream->conn = SWFDEC_RTMP_CONNECTION (conn->relay);
+ stream->conn = conn;
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
+ stream->rpc_channel = swfdec_rtmp_rpc_channel_new (conn);
+ /* FIXME: new class for multimedia plz */
+ stream->video_channel = swfdec_rtmp_rpc_channel_new (conn);
+ stream->audio_channel = swfdec_rtmp_rpc_channel_new (conn);
}
SWFDEC_AS_NATIVE (2101, 201, swfdec_net_stream_onCreate)
@@ -153,7 +167,21 @@ void
swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.onCreate (internal)");
+ SwfdecNetStream *stream;
+ SwfdecAsObject *o;
+ guint stream_id;
+
+ SWFDEC_AS_CHECK (0, NULL, "oi", &o, &stream_id);
+
+ if (!SWFDEC_IS_NET_STREAM (o->relay))
+ return;
+ stream = SWFDEC_NET_STREAM (o->relay);
+
+ stream->stream_id = stream_id;
+ stream_id = 4 + ((stream_id - 1 % 12) * 5);
+ swfdec_rtmp_channel_register (stream->rpc_channel, stream_id);
+ swfdec_rtmp_channel_register (stream->video_channel, stream_id + 1);
+ swfdec_rtmp_channel_register (stream->audio_channel, stream_id + 2);
}
SWFDEC_AS_NATIVE (2101, 202, swfdec_net_stream_send_connection)
@@ -161,6 +189,18 @@ void
swfdec_net_stream_send_connection (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.send_connection (internal)");
+ SwfdecNetStream *stream;
+ SwfdecAsObject *o, *ret_cb = NULL;
+ SwfdecAsValue name;
+
+ SWFDEC_AS_CHECK (0, NULL, "ov|O", &o, &name, &ret_cb);
+
+ if (!SWFDEC_IS_NET_STREAM (o->relay))
+ return;
+ stream = SWFDEC_NET_STREAM (o->relay);
+
+ swfdec_rtmp_rpc_channel_send (SWFDEC_RTMP_RPC_CHANNEL (
+ stream->rpc_channel), name,
+ ret_cb, MAX (3, argc) - 3, argv + 3);
}
diff --git a/swfdec/swfdec_net_stream.h b/swfdec/swfdec_net_stream.h
index 93fc1fb..89297b8 100644
--- a/swfdec/swfdec_net_stream.h
+++ b/swfdec/swfdec_net_stream.h
@@ -39,9 +39,10 @@ struct _SwfdecNetStream {
SwfdecAsRelay relay;
SwfdecRtmpConnection * conn; /* the connection in use */
- SwfdecRtmpChannel * audio_channel; /* channel used for audio */
- SwfdecRtmpChannel * video_channel; /* channel used for video */
+ guint stream_id; /* id of this stream */
SwfdecRtmpChannel * rpc_channel; /* channel used for RPC */
+ SwfdecRtmpChannel * video_channel; /* channel used for video */
+ SwfdecRtmpChannel * audio_channel; /* channel used for audio */
};
struct _SwfdecNetStreamClass {
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 3567fd7..b667d79 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -117,7 +117,6 @@ swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
gsize i;
g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
- g_return_if_fail (channel->id > 0);
g_return_if_fail (header != NULL);
g_return_if_fail (data != NULL);
@@ -136,7 +135,8 @@ swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
swfdec_buffer_queue_push (channel->send_queue, swfdec_bots_close (bots));
}
- swfdec_rtmp_socket_send (channel->conn->socket);
+ if (swfdec_rtmp_channel_is_registered (channel))
+ swfdec_rtmp_socket_send (channel->conn->socket);
}
static int
commit 1c95497cf0c535a815ce993f9903a46b0a6e4504
Author: Benjamin Otte <otte at gnome.org>
Date: Fri Dec 5 22:52:57 2008 +0000
add a FIXME for channel numbers that are too big
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 3fd6e33..3567fd7 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -156,6 +156,11 @@ swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel, guint id)
g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
g_return_if_fail (!swfdec_rtmp_channel_is_registered (channel));
g_return_if_fail (id > 1);
+
+ if (id >= 65536 + 64) {
+ SWFDEC_FIXME ("figure out how huge ids (like %u) are handled. Channel registration failed", id);
+ return;
+ }
conn = channel->conn;
conn->channels = g_list_insert_sorted (conn->channels, channel,
commit 74278993abf92672a04e896bc57c77170d664708
Author: Benjamin Otte <otte at gnome.org>
Date: Fri Dec 5 22:45:48 2008 +0000
hardcode block size to 128 bytes
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 9c87a94..3fd6e33 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -107,7 +107,6 @@ swfdec_rtmp_channel_init (SwfdecRtmpChannel *channel)
channel->recv_queue = swfdec_buffer_queue_new ();
swfdec_rtmp_header_invalidate (&channel->send_cache);
channel->send_queue = swfdec_buffer_queue_new ();
- channel->block_size = 128;
}
void
@@ -127,13 +126,13 @@ swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
swfdec_rtmp_header_diff (header, &channel->send_cache));
swfdec_rtmp_header_copy (&channel->send_cache, header);
- for (i = 0; i < data->length; i += channel->block_size) {
+ for (i = 0; i < data->length; i += SWFDEC_RTMP_BLOCK_SIZE) {
if (i != 0) {
/* write a continuation header */
bots = swfdec_bots_new ();
swfdec_rtmp_header_write (header, bots, SWFDEC_RTMP_HEADER_1_BYTE);
}
- swfdec_bots_put_data (bots, data->data + i, MIN (channel->block_size, data->length - i));
+ swfdec_bots_put_data (bots, data->data + i, MIN (SWFDEC_RTMP_BLOCK_SIZE, data->length - i));
swfdec_buffer_queue_push (channel->send_queue, swfdec_bots_close (bots));
}
@@ -163,6 +162,9 @@ swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel, guint id)
swfdec_rtmp_channel_compare);
channel->id = id;
g_object_ref (channel);
+
+ if (swfdec_buffer_queue_get_depth (channel->send_queue) > 0)
+ swfdec_rtmp_socket_send (channel->conn->socket);
}
void
diff --git a/swfdec/swfdec_rtmp_channel.h b/swfdec/swfdec_rtmp_channel.h
index 4e61a59..d7b9932 100644
--- a/swfdec/swfdec_rtmp_channel.h
+++ b/swfdec/swfdec_rtmp_channel.h
@@ -46,7 +46,6 @@ struct _SwfdecRtmpChannel {
SwfdecBufferQueue * recv_queue; /* Queue of semi-assembled packages when receiving */
SwfdecRtmpHeader send_cache; /* cached header info for sending data */
SwfdecBufferQueue * send_queue; /* Queue of outgoing waiting for delivery */
- guint block_size; /* maximum size for a single message block (FIXME: is this constant?) */
};
struct _SwfdecRtmpChannelClass {
commit bc7891f07dc527c457f5b5f45cd62d74af59815e
Author: Benjamin Otte <otte at gnome.org>
Date: Fri Dec 5 22:43:26 2008 +0000
use a list for channels, so we can add more than 64
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 45c6c84..9c87a94 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -140,35 +140,45 @@ swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
swfdec_rtmp_socket_send (channel->conn->socket);
}
+static int
+swfdec_rtmp_channel_compare (gconstpointer a, gconstpointer b)
+{
+ SwfdecRtmpChannel *ca = (SwfdecRtmpChannel *) a;
+ SwfdecRtmpChannel *cb = (SwfdecRtmpChannel *) b;
+
+ return cb->id - ca->id;
+}
+
void
swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel, guint id)
{
+ SwfdecRtmpConnection *conn;
+
g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
- g_return_if_fail (channel->id == 0);
- g_return_if_fail (id < 64);
+ g_return_if_fail (!swfdec_rtmp_channel_is_registered (channel));
+ g_return_if_fail (id > 1);
+ conn = channel->conn;
+ conn->channels = g_list_insert_sorted (conn->channels, channel,
+ swfdec_rtmp_channel_compare);
channel->id = id;
- if (channel->conn->channels[id] != NULL) {
- SWFDEC_ERROR ("channel %u is already in use", id);
- return;
- }
g_object_ref (channel);
- channel->conn->channels[id] = channel;
}
void
swfdec_rtmp_channel_unregister (SwfdecRtmpChannel *channel)
{
- guint id;
-
g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
- id = channel->id;
- channel->id = 0;
+ if (!swfdec_rtmp_channel_is_registered (channel))
+ return;
- if (channel->conn->channels[id] == channel) {
- channel->conn->channels[id] = NULL;
- g_object_unref (channel);
+ if (channel->conn->last_send->data == channel) {
+ channel->conn->last_send = channel->conn->last_send->next ?
+ channel->conn->last_send->next : channel->conn->last_send->prev;
}
+ channel->conn->channels = g_list_remove (channel->conn->channels, channel);
+ channel->id = 0;
+ g_object_unref (channel);
}
diff --git a/swfdec/swfdec_rtmp_channel.h b/swfdec/swfdec_rtmp_channel.h
index 203e114..4e61a59 100644
--- a/swfdec/swfdec_rtmp_channel.h
+++ b/swfdec/swfdec_rtmp_channel.h
@@ -38,8 +38,9 @@ typedef struct _SwfdecRtmpChannelClass SwfdecRtmpChannelClass;
struct _SwfdecRtmpChannel {
GObject object;
- SwfdecRtmpConnection * conn; /* Connection this channel belongs to or NULL if not registered */
- guint id; /* id (0-63) inside connection */
+ SwfdecRtmpConnection * conn; /* Connection this channel belongs to */
+ guint id; /* id inside connection or 0 if no connection */
+
GTimeVal timestamp; /* timestamp for various uses - set when constructing */
SwfdecRtmpHeader recv_cache; /* cached header info for receiving data */
SwfdecBufferQueue * recv_queue; /* Queue of semi-assembled packages when receiving */
@@ -64,6 +65,7 @@ void swfdec_rtmp_channel_send (SwfdecRtmpChannel * channel,
SwfdecBuffer * data);
#define swfdec_rtmp_channel_get_time(channel, tv) (swfdec_as_context_get_time (swfdec_gc_object_get_context ((channel)->conn), tv))
+#define swfdec_rtmp_channel_is_registered(channel) ((channel)->id > 0)
void swfdec_rtmp_channel_register (SwfdecRtmpChannel * channel,
guint id);
void swfdec_rtmp_channel_unregister (SwfdecRtmpChannel * channel);
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index cd14944..f028ca8 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -41,14 +41,13 @@ static void
swfdec_rtmp_connection_mark (SwfdecGcObject *object)
{
SwfdecRtmpConnection *conn = SWFDEC_RTMP_CONNECTION (object);
- guint i;
-
- for (i = 0; i < 64; i++) {
- if (conn->channels[i]) {
- SwfdecRtmpChannelClass *klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (conn->channels[i]);
- if (klass->mark)
- klass->mark (conn->channels[i]);
- }
+ GList *walk;
+
+ for (walk = conn->channels; walk; walk = walk->next) {
+ SwfdecRtmpChannel *channel = walk->data;
+ SwfdecRtmpChannelClass *klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
+ if (klass->mark)
+ klass->mark (channel);
}
SWFDEC_GC_OBJECT_CLASS (swfdec_rtmp_connection_parent_class)->mark (object);
@@ -103,15 +102,15 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
if (conn->error)
return;
- channel = swfdec_rtmp_handshake_channel_new (conn);
- swfdec_rtmp_channel_register (channel, 0);
- g_object_unref (channel);
+ conn->handshake = swfdec_rtmp_handshake_channel_new (conn);
channel = swfdec_rtmp_control_channel_new (conn);
swfdec_rtmp_channel_register (channel, 2);
g_object_unref (channel);
channel = swfdec_rtmp_rpc_channel_new (conn);
swfdec_rtmp_channel_register (channel, 3);
g_object_unref (channel);
+ conn->last_send = conn->channels;
+
swfdec_rtmp_handshake_channel_start (SWFDEC_RTMP_HANDSHAKE_CHANNEL (
swfdec_rtmp_connection_get_handshake_channel (conn)));
}
@@ -119,16 +118,10 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
void
swfdec_rtmp_connection_close (SwfdecRtmpConnection *conn)
{
- guint i;
-
g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
- for (i = 0; i < 64; i++) {
- if (conn->channels[i] == NULL)
- continue;
- swfdec_rtmp_channel_unregister (conn->channels[i]);
- g_assert (conn->channels[i] == NULL);
- }
+ while (conn->channels)
+ swfdec_rtmp_channel_unregister (conn->channels->data);
if (conn->socket) {
g_object_unref (conn->socket);
@@ -184,8 +177,21 @@ swfdec_rtmp_connection_on_status (SwfdecRtmpConnection *conn, SwfdecAsValue valu
SwfdecRtmpChannel *
swfdec_rtmp_connection_get_channel (SwfdecRtmpConnection *conn, guint id)
{
+ SwfdecRtmpChannel *channel;
+ GList *walk;
+
g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+ g_return_val_if_fail (conn->channels != NULL, NULL);
+
+ for (walk = conn->channels; walk; walk = walk->next) {
+ channel = walk->data;
+ if (channel->id < id)
+ continue;
+ if (channel->id == id)
+ return channel;
+ return NULL;
+ }
- return conn->channels[id];
+ return NULL;
}
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index e86f556..cee8aaf 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -52,8 +52,9 @@ struct _SwfdecRtmpConnection {
SwfdecURL * url; /* URL in use by this connection */
SwfdecSandbox * sandbox; /* sandbox we execute functions in or NULL */
SwfdecRtmpSocket * socket; /* socket we're using for read/write */
- SwfdecRtmpChannel * channels[64]; /* the channels in use by this connection */
- guint send_channel; /* last channel data was sent from (ensures round-robin) */
+ GList * channels; /* list of channels in use by this connection (ordered by channel) */
+ GList * last_send; /* list entry of last channel sent to */
+ SwfdecRtmpChannel * handshake; /* channel used for doing initial handshake or NULL */
char * error; /* NULL or debug string for error message */
};
@@ -81,9 +82,9 @@ void swfdec_rtmp_connection_errorv (SwfdecRtmpConnection * conn,
void swfdec_rtmp_connection_on_status (SwfdecRtmpConnection * conn,
SwfdecAsValue value);
-#define swfdec_rtmp_connection_get_handshake_channel(conn) ((conn)->channels[0])
-#define swfdec_rtmp_connection_get_command_channel(conn) ((conn)->channels[2])
-#define swfdec_rtmp_connection_get_rpc_channel(conn) ((conn)->channels[3])
+#define swfdec_rtmp_connection_get_handshake_channel(conn) ((conn)->handshake)
+#define swfdec_rtmp_connection_get_command_channel(conn) (swfdec_rtmp_connection_get_channel (conn, 2))
+#define swfdec_rtmp_connection_get_rpc_channel(conn) (swfdec_rtmp_connection_get_channel (conn, 3))
G_END_DECLS
diff --git a/swfdec/swfdec_rtmp_handshake_channel.c b/swfdec/swfdec_rtmp_handshake_channel.c
index 33ffb62..0a50d64 100644
--- a/swfdec/swfdec_rtmp_handshake_channel.c
+++ b/swfdec/swfdec_rtmp_handshake_channel.c
@@ -285,8 +285,9 @@ swfdec_rtmp_handshake_channel_connected (SwfdecRtmpHandshakeChannel *shake,
SWFDEC_ERROR ("no 2nd argument in connect reply");
}
- swfdec_rtmp_channel_unregister (SWFDEC_RTMP_CHANNEL (shake));
+ conn->handshake = NULL;
swfdec_rtmp_socket_send (conn->socket);
+ g_object_unref (shake);
}
SwfdecRtmpChannel *
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 4eb7a42..9e05577 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -117,8 +117,9 @@ SwfdecBuffer *
swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
{
SwfdecRtmpConnection *conn;
+ SwfdecRtmpChannel *channel;
SwfdecBuffer *buffer;
- guint i;
+ GList *walk;
g_return_val_if_fail (SWFDEC_IS_RTMP_SOCKET (socket), NULL);
@@ -128,17 +129,17 @@ swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
return swfdec_buffer_queue_pull_buffer (swfdec_rtmp_connection_get_handshake_channel (conn)->send_queue);
}
- i = conn->send_channel;
+ walk = conn->last_send;
+ g_assert (walk);
do {
- i = (i + 1) % 64;
- if (conn->channels[i] == NULL)
- continue;
- buffer = swfdec_buffer_queue_pull_buffer (conn->channels[i]->send_queue);
+ walk = walk->next ? walk->next : conn->channels;
+ channel = walk->data;
+ buffer = swfdec_buffer_queue_pull_buffer (channel->send_queue);
if (buffer) {
- conn->send_channel = i;
+ conn->last_send = walk;
return buffer;
}
- } while (i != conn->send_channel);
+ } while (walk != conn->last_send);
return NULL;
}
commit fbad225eb8ca54366416ff9eebc50c9dbb19e845
Author: Benjamin Otte <otte at gnome.org>
Date: Fri Dec 5 19:44:42 2008 +0000
add swfdec_rtmp_connection_get_handshake_channel()
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 432ae40..cd14944 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -113,7 +113,7 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
swfdec_rtmp_channel_register (channel, 3);
g_object_unref (channel);
swfdec_rtmp_handshake_channel_start (SWFDEC_RTMP_HANDSHAKE_CHANNEL (
- swfdec_rtmp_connection_get_channel (conn, 0)));
+ swfdec_rtmp_connection_get_handshake_channel (conn)));
}
void
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index e220fdb..e86f556 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -81,6 +81,7 @@ void swfdec_rtmp_connection_errorv (SwfdecRtmpConnection * conn,
void swfdec_rtmp_connection_on_status (SwfdecRtmpConnection * conn,
SwfdecAsValue value);
+#define swfdec_rtmp_connection_get_handshake_channel(conn) ((conn)->channels[0])
#define swfdec_rtmp_connection_get_command_channel(conn) ((conn)->channels[2])
#define swfdec_rtmp_connection_get_rpc_channel(conn) ((conn)->channels[3])
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index ca3e680..95de86c 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -108,9 +108,9 @@ swfdec_rtmp_rpc_channel_receive_reply (SwfdecRtmpChannel *channel,
SWFDEC_FIXME ("more than 2 values in a reply?");
}
- if (id == 1 && swfdec_rtmp_connection_get_channel (channel->conn, 0)) {
+ if (id == 1 && swfdec_rtmp_connection_get_handshake_channel (channel->conn)) {
swfdec_rtmp_handshake_channel_connected (SWFDEC_RTMP_HANDSHAKE_CHANNEL (
- swfdec_rtmp_connection_get_channel (channel->conn, 0)),
+ swfdec_rtmp_connection_get_handshake_channel (channel->conn)),
i, val);
} else {
if (!SWFDEC_AS_VALUE_IS_NULL (val[0])) {
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 8190d7a..4eb7a42 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -124,8 +124,8 @@ swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
conn = socket->conn;
- if (G_UNLIKELY (swfdec_rtmp_connection_get_channel (conn, 0))) {
- return swfdec_buffer_queue_pull_buffer (swfdec_rtmp_connection_get_channel (conn, 0)->send_queue);
+ if (G_UNLIKELY (swfdec_rtmp_connection_get_handshake_channel (conn))) {
+ return swfdec_buffer_queue_pull_buffer (swfdec_rtmp_connection_get_handshake_channel (conn)->send_queue);
}
i = conn->send_channel;
@@ -157,8 +157,9 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
conn = sock->conn;
- if (G_UNLIKELY (swfdec_rtmp_connection_get_channel (conn, 0))) {
- SwfdecRtmpHandshakeChannel *shake = SWFDEC_RTMP_HANDSHAKE_CHANNEL (swfdec_rtmp_connection_get_channel (conn, 0));
+ if (G_UNLIKELY (swfdec_rtmp_connection_get_handshake_channel (conn))) {
+ SwfdecRtmpHandshakeChannel *shake = SWFDEC_RTMP_HANDSHAKE_CHANNEL (
+ swfdec_rtmp_connection_get_handshake_channel (conn));
if (shake->reply == NULL) {
while (swfdec_rtmp_handshake_channel_receive (shake, queue));
return;
commit e9e5189513b2765d66cc89f3ad1dfcca753bbc23
Author: Benjamin Otte <otte at gnome.org>
Date: Fri Dec 5 15:07:54 2008 +0000
add swfdec_rtmp_connection_get_channel() and use it
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 4a9cc1c..45c6c84 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -137,8 +137,7 @@ swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
swfdec_buffer_queue_push (channel->send_queue, swfdec_bots_close (bots));
}
- if (channel->conn->channels[0] == NULL)
- swfdec_rtmp_socket_send (channel->conn->socket);
+ swfdec_rtmp_socket_send (channel->conn->socket);
}
void
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index dad7d19..432ae40 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -112,7 +112,8 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
channel = swfdec_rtmp_rpc_channel_new (conn);
swfdec_rtmp_channel_register (channel, 3);
g_object_unref (channel);
- swfdec_rtmp_handshake_channel_start (SWFDEC_RTMP_HANDSHAKE_CHANNEL (conn->channels[0]));
+ swfdec_rtmp_handshake_channel_start (SWFDEC_RTMP_HANDSHAKE_CHANNEL (
+ swfdec_rtmp_connection_get_channel (conn, 0)));
}
void
@@ -179,3 +180,12 @@ swfdec_rtmp_connection_on_status (SwfdecRtmpConnection *conn, SwfdecAsValue valu
swfdec_as_relay_call (SWFDEC_AS_RELAY (conn), SWFDEC_AS_STR_onStatus, 1, &value, NULL);
}
+
+SwfdecRtmpChannel *
+swfdec_rtmp_connection_get_channel (SwfdecRtmpConnection *conn, guint id)
+{
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+
+ return conn->channels[id];
+}
+
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index 3fd3248..e220fdb 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -70,6 +70,8 @@ void swfdec_rtmp_connection_close (SwfdecRtmpConnection * conn);
void swfdec_rtmp_connection_receive (SwfdecRtmpConnection * conn,
SwfdecBufferQueue * queue);
void swfdec_rtmp_connection_send (SwfdecRtmpConnection * conn);
+SwfdecRtmpChannel * swfdec_rtmp_connection_get_channel (SwfdecRtmpConnection * conn,
+ guint id);
void swfdec_rtmp_connection_error (SwfdecRtmpConnection * conn,
const char * error,
...) G_GNUC_PRINTF (2, 3);
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index a1ad1d4..ca3e680 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -108,8 +108,9 @@ swfdec_rtmp_rpc_channel_receive_reply (SwfdecRtmpChannel *channel,
SWFDEC_FIXME ("more than 2 values in a reply?");
}
- if (id == 1 && SWFDEC_IS_RTMP_HANDSHAKE_CHANNEL (channel->conn->channels[0])) {
- swfdec_rtmp_handshake_channel_connected (SWFDEC_RTMP_HANDSHAKE_CHANNEL (channel->conn->channels[0]),
+ if (id == 1 && swfdec_rtmp_connection_get_channel (channel->conn, 0)) {
+ swfdec_rtmp_handshake_channel_connected (SWFDEC_RTMP_HANDSHAKE_CHANNEL (
+ swfdec_rtmp_connection_get_channel (channel->conn, 0)),
i, val);
} else {
if (!SWFDEC_AS_VALUE_IS_NULL (val[0])) {
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 16706ce..8190d7a 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -124,9 +124,8 @@ swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
conn = socket->conn;
- if (G_UNLIKELY (conn->channels[0] &&
- SWFDEC_IS_RTMP_HANDSHAKE_CHANNEL (conn->channels[0]))) {
- return swfdec_buffer_queue_pull_buffer (conn->channels[0]->send_queue);
+ if (G_UNLIKELY (swfdec_rtmp_connection_get_channel (conn, 0))) {
+ return swfdec_buffer_queue_pull_buffer (swfdec_rtmp_connection_get_channel (conn, 0)->send_queue);
}
i = conn->send_channel;
@@ -158,11 +157,10 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
conn = sock->conn;
- if (G_UNLIKELY (conn->channels[0] &&
- SWFDEC_IS_RTMP_HANDSHAKE_CHANNEL (conn->channels[0]))) {
- SwfdecRtmpHandshakeChannel *shake = SWFDEC_RTMP_HANDSHAKE_CHANNEL (conn->channels[0]);
+ if (G_UNLIKELY (swfdec_rtmp_connection_get_channel (conn, 0))) {
+ SwfdecRtmpHandshakeChannel *shake = SWFDEC_RTMP_HANDSHAKE_CHANNEL (swfdec_rtmp_connection_get_channel (conn, 0));
if (shake->reply == NULL) {
- while (swfdec_rtmp_handshake_channel_receive (SWFDEC_RTMP_HANDSHAKE_CHANNEL (conn->channels[0]), queue));
+ while (swfdec_rtmp_handshake_channel_receive (shake, queue));
return;
}
}
@@ -181,7 +179,7 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
break;
swfdec_bits_init (&bits, buffer);
i = swfdec_rtmp_header_peek_channel (&bits);
- channel = conn->channels[i];
+ channel = swfdec_rtmp_connection_get_channel (conn, i);
if (channel == NULL) {
swfdec_rtmp_connection_error (conn,
"message on unknown channel %u, what now?", i);
commit ccaf078ea5ee2ae634c3d8506074869141fd682a
Author: Benjamin Otte <otte at gnome.org>
Date: Fri Dec 5 12:56:43 2008 +0000
rework channel reading to allow channels > 64
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 535f1c7..4a9cc1c 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -118,6 +118,7 @@ swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
gsize i;
g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
+ g_return_if_fail (channel->id > 0);
g_return_if_fail (header != NULL);
g_return_if_fail (data != NULL);
@@ -136,54 +137,10 @@ swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
swfdec_buffer_queue_push (channel->send_queue, swfdec_bots_close (bots));
}
- if (channel->conn)
+ if (channel->conn->channels[0] == NULL)
swfdec_rtmp_socket_send (channel->conn->socket);
}
-gboolean
-swfdec_rtmp_channel_receive (SwfdecRtmpChannel *channel, SwfdecBufferQueue *queue,
- SwfdecRtmpHeaderSize header_size)
-{
- SwfdecRtmpHeader header;
- SwfdecBuffer *buffer;
- SwfdecBits bits;
- gsize size, remaining_size;
-
- size = swfdec_rtmp_header_size_get (header_size);
- if (size > 4 && swfdec_buffer_queue_get_depth (channel->recv_queue)) {
- SWFDEC_ERROR ("received new command, but old command not processed yet, dropping old command");
- swfdec_buffer_queue_flush (channel->recv_queue, swfdec_buffer_queue_get_depth (channel->recv_queue));
- }
-
- buffer = swfdec_buffer_queue_peek (queue, size);
- if (buffer == NULL)
- return FALSE;
-
- swfdec_bits_init (&bits, buffer);
- swfdec_rtmp_header_copy (&header, &channel->recv_cache);
- swfdec_rtmp_header_read (&header, &bits);
- swfdec_buffer_unref (buffer);
- remaining_size = header.size - swfdec_buffer_queue_get_depth (channel->recv_queue);
- remaining_size = MIN (remaining_size, channel->block_size);
- if (swfdec_buffer_queue_get_depth (queue) < size + remaining_size)
- return FALSE;
-
- swfdec_rtmp_header_copy (&channel->recv_cache, &header);
- swfdec_buffer_queue_flush (queue, size);
- buffer = swfdec_buffer_queue_pull (queue, remaining_size);
- swfdec_buffer_queue_push (channel->recv_queue, buffer);
-
- size = swfdec_buffer_queue_get_depth (channel->recv_queue);
- g_assert (header.size >= size);
- if (header.size == size) {
- SwfdecRtmpChannelClass *klass;
- buffer = swfdec_buffer_queue_pull (channel->recv_queue, size);
- klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
- klass->receive (channel, &header, buffer);
- }
- return TRUE;
-}
-
void
swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel, guint id)
{
diff --git a/swfdec/swfdec_rtmp_channel.h b/swfdec/swfdec_rtmp_channel.h
index cbda82d..203e114 100644
--- a/swfdec/swfdec_rtmp_channel.h
+++ b/swfdec/swfdec_rtmp_channel.h
@@ -62,9 +62,6 @@ GType swfdec_rtmp_channel_get_type (void);
void swfdec_rtmp_channel_send (SwfdecRtmpChannel * channel,
const SwfdecRtmpHeader *header,
SwfdecBuffer * data);
-gboolean swfdec_rtmp_channel_receive (SwfdecRtmpChannel * channel,
- SwfdecBufferQueue * queue,
- SwfdecRtmpHeaderSize header_size);
#define swfdec_rtmp_channel_get_time(channel, tv) (swfdec_as_context_get_time (swfdec_gc_object_get_context ((channel)->conn), tv))
void swfdec_rtmp_channel_register (SwfdecRtmpChannel * channel,
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index a246148..3fd3248 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -28,6 +28,9 @@
G_BEGIN_DECLS
+/* size of a packet block */
+#define SWFDEC_RTMP_BLOCK_SIZE 128
+
/* forward declarations */
typedef struct _SwfdecRtmpChannel SwfdecRtmpChannel;
typedef struct _SwfdecRtmpSocket SwfdecRtmpSocket;
diff --git a/swfdec/swfdec_rtmp_control_channel.c b/swfdec/swfdec_rtmp_control_channel.c
index 9aca56f..a7a8096 100644
--- a/swfdec/swfdec_rtmp_control_channel.c
+++ b/swfdec/swfdec_rtmp_control_channel.c
@@ -111,7 +111,6 @@ swfdec_rtmp_control_channel_receive (SwfdecRtmpChannel *channel,
SWFDEC_FIXME ("what to do with header type %u?", header->type);
break;
}
- swfdec_buffer_unref (buffer);
}
static void
diff --git a/swfdec/swfdec_rtmp_header.c b/swfdec/swfdec_rtmp_header.c
index 4efd722..cb3f6bf 100644
--- a/swfdec/swfdec_rtmp_header.c
+++ b/swfdec/swfdec_rtmp_header.c
@@ -24,11 +24,26 @@
#include "swfdec_rtmp_header.h"
gsize
-swfdec_rtmp_header_size_get (SwfdecRtmpHeaderSize size)
+swfdec_rtmp_header_peek_size (guint first_byte)
{
static const gsize sizes[] = { 12, 8, 4, 1 };
-
- return sizes[size];
+ gsize result;
+
+ g_return_val_if_fail (first_byte < 256, 0);
+
+ result = sizes[first_byte >> 6];
+ switch (first_byte & 63) {
+ case 0:
+ result++;
+ break;
+ case 1:
+ result += 2;
+ break;
+ default:
+ break;
+ }
+
+ return result;
}
void
@@ -49,6 +64,16 @@ swfdec_rtmp_header_read (SwfdecRtmpHeader *header, SwfdecBits *bits)
size = swfdec_bits_getbits (bits, 2);
header->channel = swfdec_bits_getbits (bits, 6);
+ switch (header->channel) {
+ case 0:
+ header->channel = swfdec_bits_get_u8 (bits) + 64;
+ break;
+ case 1:
+ header->channel = swfdec_bits_get_u16 (bits) + 64;
+ break;
+ default:
+ break;
+ }
if (size == SWFDEC_RTMP_HEADER_1_BYTE)
return;
header->timestamp = swfdec_bits_get_bu24 (bits);
@@ -61,6 +86,31 @@ swfdec_rtmp_header_read (SwfdecRtmpHeader *header, SwfdecBits *bits)
header->stream = swfdec_bits_get_u32 (bits);
}
+guint
+swfdec_rtmp_header_peek_channel (SwfdecBits *bits)
+{
+ SwfdecBits real;
+ guint channel;
+
+ g_return_val_if_fail (bits != NULL, 0);
+
+ real = *bits;
+ swfdec_bits_getbits (&real, 2);
+ channel = swfdec_bits_getbits (&real, 6);
+ switch (channel) {
+ case 0:
+ channel = swfdec_bits_get_u8 (&real) + 64;
+ break;
+ case 1:
+ channel = swfdec_bits_get_u16 (&real) + 64;
+ break;
+ default:
+ break;
+ }
+
+ return channel;
+}
+
void
swfdec_rtmp_header_write (const SwfdecRtmpHeader *header, SwfdecBots *bots,
SwfdecRtmpHeaderSize size)
@@ -69,7 +119,15 @@ swfdec_rtmp_header_write (const SwfdecRtmpHeader *header, SwfdecBots *bots,
g_return_if_fail (bots != NULL);
swfdec_bots_put_bits (bots, size, 2);
- swfdec_bots_put_bits (bots, header->channel, 6);
+ if (header->channel >= 320) {
+ swfdec_bots_put_bits (bots, header->channel, 1);
+ swfdec_bots_put_u16 (bots, header->channel - 64);
+ } else if (header->channel >= 64) {
+ swfdec_bots_put_bits (bots, header->channel, 0);
+ swfdec_bots_put_u8 (bots, header->channel - 64);
+ } else {
+ swfdec_bots_put_bits (bots, header->channel, 6);
+ }
if (size == SWFDEC_RTMP_HEADER_1_BYTE)
return;
swfdec_bots_put_bu24 (bots, header->timestamp);
diff --git a/swfdec/swfdec_rtmp_header.h b/swfdec/swfdec_rtmp_header.h
index d9c324c..587ff73 100644
--- a/swfdec/swfdec_rtmp_header.h
+++ b/swfdec/swfdec_rtmp_header.h
@@ -63,13 +63,15 @@ struct _SwfdecRtmpHeader {
#define SWFDEC_RTMP_HEADER_INVALID { (guint) -1, 0, 0, 0, 0 }
-gsize swfdec_rtmp_header_size_get (SwfdecRtmpHeaderSize size);
+gsize swfdec_rtmp_header_peek_size (guint first_byte);
+guint swfdec_rtmp_header_peek_channel (SwfdecBits * bits);
void swfdec_rtmp_header_invalidate (SwfdecRtmpHeader * header);
#define swfdec_rtmp_header_copy(dest, src) *(dest) = *(src)
void swfdec_rtmp_header_read (SwfdecRtmpHeader * header,
SwfdecBits * bits);
+
void swfdec_rtmp_header_write (const SwfdecRtmpHeader * header,
SwfdecBots * bots,
SwfdecRtmpHeaderSize size);
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index 61daf17..a1ad1d4 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -198,7 +198,6 @@ swfdec_rtmp_rpc_channel_receive (SwfdecRtmpChannel *channel,
}
swfdec_sandbox_unuse (channel->conn->sandbox);
swfdec_amf_context_free (cx);
- swfdec_buffer_unref (buffer);
}
static void
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index bd015c7..16706ce 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -146,11 +146,12 @@ swfdec_rtmp_socket_next_buffer (SwfdecRtmpSocket *socket)
void
swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
{
+ SwfdecRtmpConnection *conn;
+ SwfdecRtmpChannel *channel;
+ SwfdecRtmpHeader header;
SwfdecBuffer *buffer;
SwfdecBits bits;
- SwfdecRtmpHeaderSize header_size;
- SwfdecRtmpConnection *conn;
- guint channel;
+ guint i, remaining, header_size;
g_return_if_fail (SWFDEC_IS_RTMP_SOCKET (sock));
g_return_if_fail (queue != NULL);
@@ -167,17 +168,53 @@ swfdec_rtmp_socket_receive (SwfdecRtmpSocket *sock, SwfdecBufferQueue *queue)
}
do {
+ /* determine size of header */
buffer = swfdec_buffer_queue_peek (queue, 1);
if (buffer == NULL)
break;
- swfdec_bits_init (&bits, buffer);
- header_size = swfdec_bits_getbits (&bits, 2);
- channel = swfdec_bits_getbits (&bits, 6);
+ header_size = swfdec_rtmp_header_peek_size (buffer->data[0]);
swfdec_buffer_unref (buffer);
- if (conn->channels[channel] == NULL) {
- SWFDEC_FIXME ("message on unknown channel %u, what now?", channel);
+
+ /* read header */
+ buffer = swfdec_buffer_queue_peek (queue, header_size);
+ if (buffer == NULL)
break;
+ swfdec_bits_init (&bits, buffer);
+ i = swfdec_rtmp_header_peek_channel (&bits);
+ channel = conn->channels[i];
+ if (channel == NULL) {
+ swfdec_rtmp_connection_error (conn,
+ "message on unknown channel %u, what now?", i);
+ return;
+ }
+ if (header_size >= 4 && swfdec_buffer_queue_get_depth (channel->recv_queue)) {
+ SWFDEC_ERROR ("not a continuation header, but old command not finished yet, dropping old command");
+ swfdec_buffer_queue_flush (channel->recv_queue, swfdec_buffer_queue_get_depth (channel->recv_queue));
+ }
+ swfdec_rtmp_header_copy (&header, &channel->recv_cache);
+ swfdec_rtmp_header_read (&header, &bits);
+ swfdec_buffer_unref (buffer);
+
+ /* read the data chunk */
+ remaining = header.size - swfdec_buffer_queue_get_depth (channel->recv_queue);
+ remaining = MIN (remaining, SWFDEC_RTMP_BLOCK_SIZE);
+ if (header_size + remaining > swfdec_buffer_queue_get_depth (queue))
+ return;
+ swfdec_buffer_queue_flush (queue, header_size);
+ buffer = swfdec_buffer_queue_pull (queue, remaining);
+ g_assert (buffer);
+ swfdec_buffer_queue_push (channel->recv_queue, buffer);
+ swfdec_rtmp_header_copy (&channel->recv_cache, &header);
+
+ /* process the buffer if it's received completely */
+ buffer = swfdec_buffer_queue_pull (channel->recv_queue, header.size);
+ if (buffer) {
+ SwfdecRtmpChannelClass *klass = SWFDEC_RTMP_CHANNEL_GET_CLASS (channel);
+
+ g_assert (swfdec_buffer_queue_get_depth (channel->recv_queue) == 0);
+ klass->receive (channel, &header, buffer);
+ swfdec_buffer_unref (buffer);
}
- } while (swfdec_rtmp_channel_receive (conn->channels[channel], queue, header_size));
+ } while (TRUE);
}
commit 85d40b9f804b4d7adc4433ce8c329a40e8efbf3b
Author: Benjamin Otte <otte at gnome.org>
Date: Thu Dec 4 09:41:45 2008 +0000
change channel construction
previously, channels were constructed with their correct channel id.
This is impossible for handling NetStream, where the channel id is only
known after the createStream RPC call succeeded.
diff --git a/swfdec/swfdec_rtmp_channel.c b/swfdec/swfdec_rtmp_channel.c
index 67725ae..535f1c7 100644
--- a/swfdec/swfdec_rtmp_channel.c
+++ b/swfdec/swfdec_rtmp_channel.c
@@ -28,9 +28,48 @@
/*** SwfdecRtmpChannel ***/
+enum {
+ PROP_0,
+ PROP_CONNECTION
+};
+
G_DEFINE_ABSTRACT_TYPE (SwfdecRtmpChannel, swfdec_rtmp_channel, G_TYPE_OBJECT)
static void
+swfdec_rtmp_channel_get_property (GObject *object, guint param_id, GValue *value,
+ GParamSpec * pspec)
+{
+ SwfdecRtmpChannel *channel = SWFDEC_RTMP_CHANNEL (object);
+
+ switch (param_id) {
+ case PROP_CONNECTION:
+ g_value_set_object (value, channel->conn);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+swfdec_rtmp_channel_set_property (GObject *object, guint param_id, const GValue *value,
+ GParamSpec * pspec)
+{
+ SwfdecRtmpChannel *channel = SWFDEC_RTMP_CHANNEL (object);
+
+ switch (param_id) {
+ case PROP_CONNECTION:
+ channel->conn = g_value_get_object (value);
+ g_assert (channel->conn != NULL);
+ swfdec_rtmp_channel_get_time (channel, &channel->timestamp);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
swfdec_rtmp_channel_dispose (GObject *object)
{
SwfdecRtmpChannel *channel = SWFDEC_RTMP_CHANNEL (object);
@@ -53,6 +92,12 @@ swfdec_rtmp_channel_class_init (SwfdecRtmpChannelClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = swfdec_rtmp_channel_dispose;
+ object_class->get_property = swfdec_rtmp_channel_get_property;
+ object_class->set_property = swfdec_rtmp_channel_set_property;
+
+ g_object_class_install_property (object_class, PROP_CONNECTION,
+ g_param_spec_object ("connection", "connection", "RTMP connection this channel belongs to",
+ SWFDEC_TYPE_RTMP_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
@@ -91,7 +136,8 @@ swfdec_rtmp_channel_send (SwfdecRtmpChannel *channel,
swfdec_buffer_queue_push (channel->send_queue, swfdec_bots_close (bots));
}
- swfdec_rtmp_socket_send (channel->conn->socket);
+ if (channel->conn)
+ swfdec_rtmp_socket_send (channel->conn->socket);
}
gboolean
@@ -138,3 +184,35 @@ swfdec_rtmp_channel_receive (SwfdecRtmpChannel *channel, SwfdecBufferQueue *queu
return TRUE;
}
+void
+swfdec_rtmp_channel_register (SwfdecRtmpChannel *channel, guint id)
+{
+ g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
+ g_return_if_fail (channel->id == 0);
+ g_return_if_fail (id < 64);
+
+ channel->id = id;
+ if (channel->conn->channels[id] != NULL) {
+ SWFDEC_ERROR ("channel %u is already in use", id);
+ return;
+ }
+ g_object_ref (channel);
+ channel->conn->channels[id] = channel;
+}
+
+void
+swfdec_rtmp_channel_unregister (SwfdecRtmpChannel *channel)
+{
+ guint id;
+
+ g_return_if_fail (SWFDEC_IS_RTMP_CHANNEL (channel));
+
+ id = channel->id;
+ channel->id = 0;
+
+ if (channel->conn->channels[id] == channel) {
+ channel->conn->channels[id] = NULL;
+ g_object_unref (channel);
+ }
+}
+
diff --git a/swfdec/swfdec_rtmp_channel.h b/swfdec/swfdec_rtmp_channel.h
index 9ef6c77..cbda82d 100644
--- a/swfdec/swfdec_rtmp_channel.h
+++ b/swfdec/swfdec_rtmp_channel.h
@@ -38,7 +38,7 @@ typedef struct _SwfdecRtmpChannelClass SwfdecRtmpChannelClass;
struct _SwfdecRtmpChannel {
GObject object;
- SwfdecRtmpConnection * conn; /* Connection this channel belongs to (holds reference) */
+ SwfdecRtmpConnection * conn; /* Connection this channel belongs to or NULL if not registered */
guint id; /* id (0-63) inside connection */
GTimeVal timestamp; /* timestamp for various uses - set when constructing */
SwfdecRtmpHeader recv_cache; /* cached header info for receiving data */
@@ -67,6 +67,9 @@ gboolean swfdec_rtmp_channel_receive (SwfdecRtmpChannel * channel,
SwfdecRtmpHeaderSize header_size);
#define swfdec_rtmp_channel_get_time(channel, tv) (swfdec_as_context_get_time (swfdec_gc_object_get_context ((channel)->conn), tv))
+void swfdec_rtmp_channel_register (SwfdecRtmpChannel * channel,
+ guint id);
+void swfdec_rtmp_channel_unregister (SwfdecRtmpChannel * channel);
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 2015d86..dad7d19 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -87,6 +87,8 @@ swfdec_rtmp_connection_init (SwfdecRtmpConnection *rtmp_connection)
void
swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url)
{
+ SwfdecRtmpChannel *channel;
+
g_return_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn));
swfdec_rtmp_connection_close (conn);
@@ -101,9 +103,15 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
if (conn->error)
return;
- swfdec_rtmp_connection_register_channel (conn, 0, SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL);
- swfdec_rtmp_connection_register_channel (conn, 2, SWFDEC_TYPE_RTMP_CONTROL_CHANNEL);
- swfdec_rtmp_connection_register_channel (conn, 3, SWFDEC_TYPE_RTMP_RPC_CHANNEL);
+ channel = swfdec_rtmp_handshake_channel_new (conn);
+ swfdec_rtmp_channel_register (channel, 0);
+ g_object_unref (channel);
+ channel = swfdec_rtmp_control_channel_new (conn);
+ swfdec_rtmp_channel_register (channel, 2);
+ g_object_unref (channel);
+ channel = swfdec_rtmp_rpc_channel_new (conn);
+ swfdec_rtmp_channel_register (channel, 3);
+ g_object_unref (channel);
swfdec_rtmp_handshake_channel_start (SWFDEC_RTMP_HANDSHAKE_CHANNEL (conn->channels[0]));
}
@@ -117,8 +125,8 @@ swfdec_rtmp_connection_close (SwfdecRtmpConnection *conn)
for (i = 0; i < 64; i++) {
if (conn->channels[i] == NULL)
continue;
- g_object_unref (conn->channels[i]);
- conn->channels[i] = NULL;
+ swfdec_rtmp_channel_unregister (conn->channels[i]);
+ g_assert (conn->channels[i] == NULL);
}
if (conn->socket) {
@@ -131,36 +139,6 @@ swfdec_rtmp_connection_close (SwfdecRtmpConnection *conn)
}
}
-SwfdecRtmpChannel *
-swfdec_rtmp_connection_register_channel (SwfdecRtmpConnection *conn, int id,
- GType channel_type)
-{
- g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
- g_return_val_if_fail (id >= -1 && id < 64, NULL);
- g_return_val_if_fail (g_type_is_a (channel_type, SWFDEC_TYPE_RTMP_CHANNEL), NULL);
-
- if (id < 0) {
- /* FIXME: do we give out channels 0 and 1? */
- /* we can start at 4, because 2 and 3 are reserved */
- for (id = 4; id < 64; id++) {
- if (conn->channels[id] == NULL)
- break;
- }
- if (id == 64) {
- SWFDEC_ERROR ("all channels in use, what now?");
- return NULL;
- }
- }
-
- conn->channels[id] = g_object_new (channel_type, NULL);
- conn->channels[id]->conn = conn;
- conn->channels[id]->id = id;
- swfdec_as_context_get_time (swfdec_gc_object_get_context (conn),
- &conn->channels[id]->timestamp);
-
- return conn->channels[id];
-}
-
void
swfdec_rtmp_connection_error (SwfdecRtmpConnection *conn, const char *error, ...)
{
diff --git a/swfdec/swfdec_rtmp_connection.h b/swfdec/swfdec_rtmp_connection.h
index 0af68f5..a246148 100644
--- a/swfdec/swfdec_rtmp_connection.h
+++ b/swfdec/swfdec_rtmp_connection.h
@@ -78,9 +78,6 @@ void swfdec_rtmp_connection_on_status (SwfdecRtmpConnection * conn,
#define swfdec_rtmp_connection_get_command_channel(conn) ((conn)->channels[2])
#define swfdec_rtmp_connection_get_rpc_channel(conn) ((conn)->channels[3])
-SwfdecRtmpChannel * swfdec_rtmp_connection_register_channel (SwfdecRtmpConnection * conn,
- int id,
- GType channel_type);
G_END_DECLS
diff --git a/swfdec/swfdec_rtmp_control_channel.c b/swfdec/swfdec_rtmp_control_channel.c
index 6753a0d..9aca56f 100644
--- a/swfdec/swfdec_rtmp_control_channel.c
+++ b/swfdec/swfdec_rtmp_control_channel.c
@@ -138,3 +138,10 @@ swfdec_rtmp_control_channel_init (SwfdecRtmpControlChannel *command)
{
}
+SwfdecRtmpChannel *
+swfdec_rtmp_control_channel_new (SwfdecRtmpConnection *conn)
+{
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+
+ return g_object_new (SWFDEC_TYPE_RTMP_CONTROL_CHANNEL, "connection", conn, NULL);
+}
diff --git a/swfdec/swfdec_rtmp_control_channel.h b/swfdec/swfdec_rtmp_control_channel.h
index 34d839d..95baf4c 100644
--- a/swfdec/swfdec_rtmp_control_channel.h
+++ b/swfdec/swfdec_rtmp_control_channel.h
@@ -48,6 +48,8 @@ struct _SwfdecRtmpControlChannelClass {
GType swfdec_rtmp_control_channel_get_type (void);
+SwfdecRtmpChannel * swfdec_rtmp_control_channel_new (SwfdecRtmpConnection * conn);
+
G_END_DECLS
#endif
diff --git a/swfdec/swfdec_rtmp_handshake_channel.c b/swfdec/swfdec_rtmp_handshake_channel.c
index 39af245..33ffb62 100644
--- a/swfdec/swfdec_rtmp_handshake_channel.c
+++ b/swfdec/swfdec_rtmp_handshake_channel.c
@@ -285,7 +285,14 @@ swfdec_rtmp_handshake_channel_connected (SwfdecRtmpHandshakeChannel *shake,
SWFDEC_ERROR ("no 2nd argument in connect reply");
}
- g_object_unref (conn->channels[0]);
- conn->channels[0] = NULL;
+ swfdec_rtmp_channel_unregister (SWFDEC_RTMP_CHANNEL (shake));
swfdec_rtmp_socket_send (conn->socket);
}
+
+SwfdecRtmpChannel *
+swfdec_rtmp_handshake_channel_new (SwfdecRtmpConnection *conn)
+{
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+
+ return g_object_new (SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL, "connection", conn, NULL);
+}
diff --git a/swfdec/swfdec_rtmp_handshake_channel.h b/swfdec/swfdec_rtmp_handshake_channel.h
index 2d248bc..f5bcd0b 100644
--- a/swfdec/swfdec_rtmp_handshake_channel.h
+++ b/swfdec/swfdec_rtmp_handshake_channel.h
@@ -46,14 +46,16 @@ struct _SwfdecRtmpHandshakeChannelClass {
SwfdecRtmpChannelClass channel_class;
};
-GType swfdec_rtmp_handshake_channel_get_type (void);
-
-void swfdec_rtmp_handshake_channel_start (SwfdecRtmpHandshakeChannel * channel);
-gboolean swfdec_rtmp_handshake_channel_receive (SwfdecRtmpHandshakeChannel * channel,
- SwfdecBufferQueue * queue);
-void swfdec_rtmp_handshake_channel_connected (SwfdecRtmpHandshakeChannel * shake,
- guint argc,
- const SwfdecAsValue * argv);
+GType swfdec_rtmp_handshake_channel_get_type (void);
+
+SwfdecRtmpChannel * swfdec_rtmp_handshake_channel_new (SwfdecRtmpConnection * conn);
+
+void swfdec_rtmp_handshake_channel_start (SwfdecRtmpHandshakeChannel * channel);
+gboolean swfdec_rtmp_handshake_channel_receive (SwfdecRtmpHandshakeChannel * channel,
+ SwfdecBufferQueue * queue);
+void swfdec_rtmp_handshake_channel_connected (SwfdecRtmpHandshakeChannel * shake,
+ guint argc,
+ const SwfdecAsValue * argv);
G_END_DECLS
diff --git a/swfdec/swfdec_rtmp_rpc_channel.c b/swfdec/swfdec_rtmp_rpc_channel.c
index c57a33e..61daf17 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.c
+++ b/swfdec/swfdec_rtmp_rpc_channel.c
@@ -272,3 +272,10 @@ swfdec_rtmp_rpc_channel_send (SwfdecRtmpRpcChannel *rpc,
swfdec_rtmp_rpc_channel_do_send (rpc, name, id, SWFDEC_AS_VALUE_NULL, argc, argv);
}
+SwfdecRtmpChannel *
+swfdec_rtmp_rpc_channel_new (SwfdecRtmpConnection *conn)
+{
+ g_return_val_if_fail (SWFDEC_IS_RTMP_CONNECTION (conn), NULL);
+
+ return g_object_new (SWFDEC_TYPE_RTMP_RPC_CHANNEL, "connection", conn, NULL);
+}
diff --git a/swfdec/swfdec_rtmp_rpc_channel.h b/swfdec/swfdec_rtmp_rpc_channel.h
index 76ec992..cdced09 100644
--- a/swfdec/swfdec_rtmp_rpc_channel.h
+++ b/swfdec/swfdec_rtmp_rpc_channel.h
@@ -50,6 +50,8 @@ struct _SwfdecRtmpRpcChannelClass {
GType swfdec_rtmp_rpc_channel_get_type (void);
+SwfdecRtmpChannel * swfdec_rtmp_rpc_channel_new (SwfdecRtmpConnection * conn);
+
void swfdec_rtmp_rpc_channel_send_connect (SwfdecRtmpRpcChannel * rpc,
SwfdecAsValue connect);
void swfdec_rtmp_rpc_channel_send (SwfdecRtmpRpcChannel * rpc,
commit fb522f3d14a941523e26dcf88ace47636fd609d2
Author: Benjamin Otte <otte at gnome.org>
Date: Thu Dec 4 08:38:23 2008 +0000
the rtmp socket doesn't have an error state anymore
diff --git a/swfdec/swfdec_rtmp_socket.c b/swfdec/swfdec_rtmp_socket.c
index 4578f27..bd015c7 100644
--- a/swfdec/swfdec_rtmp_socket.c
+++ b/swfdec/swfdec_rtmp_socket.c
@@ -36,10 +36,7 @@ G_DEFINE_TYPE (SwfdecRtmpSocket, swfdec_rtmp_socket, G_TYPE_OBJECT)
static void
swfdec_rtmp_socket_dispose (GObject *object)
{
- SwfdecRtmpSocket *sock = SWFDEC_RTMP_SOCKET (object);
-
- g_free (sock->error);
- sock->error = NULL;
+ //SwfdecRtmpSocket *sock = SWFDEC_RTMP_SOCKET (object);
G_OBJECT_CLASS (swfdec_rtmp_socket_parent_class)->dispose (object);
}
diff --git a/swfdec/swfdec_rtmp_socket.h b/swfdec/swfdec_rtmp_socket.h
index 51d3311..63011c5 100644
--- a/swfdec/swfdec_rtmp_socket.h
+++ b/swfdec/swfdec_rtmp_socket.h
@@ -39,7 +39,6 @@ struct _SwfdecRtmpSocket {
GObject object;
SwfdecRtmpConnection *conn; /* the connection that spawned and refs us */
- char * error; /* NULL or description of error socket is in */
};
struct _SwfdecRtmpSocketClass {
commit d7aee58ad09aca8f890b5be12c2499806c85a8e5
Author: Benjamin Otte <otte at gnome.org>
Date: Thu Dec 4 08:37:54 2008 +0000
make NetStream its own object again
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 201c5b0..bb40b2b 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -321,6 +321,7 @@ noinst_HEADERS = \
swfdec_morphshape.h \
swfdec_movie.h \
swfdec_movie_clip_loader.h \
+ swfdec_net_stream.h \
swfdec_path.h \
swfdec_pattern.h \
swfdec_player_internal.h \
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index cde9348..22859b2 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -21,9 +21,51 @@
#include "config.h"
#endif
+#include "swfdec_net_stream.h"
+
+#include "swfdec_as_frame_internal.h"
#include "swfdec_as_internal.h"
#include "swfdec_debug.h"
+/*** NET STREAM ***/
+
+G_DEFINE_TYPE (SwfdecNetStream, swfdec_net_stream, SWFDEC_TYPE_AS_RELAY)
+
+static void
+swfdec_net_stream_mark (SwfdecGcObject *object)
+{
+ SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
+
+ swfdec_gc_object_mark (stream->conn);
+ /* no need to handle the channels, the connection manages them */
+
+ SWFDEC_GC_OBJECT_CLASS (swfdec_net_stream_parent_class)->mark (object);
+}
+
+static void
+swfdec_net_stream_dispose (GObject *object)
+{
+ //SwfdecNetStream *conn = SWFDEC_NET_STREAM (object);
+
+ G_OBJECT_CLASS (swfdec_net_stream_parent_class)->dispose (object);
+}
+
+static void
+swfdec_net_stream_class_init (SwfdecNetStreamClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
+
+ object_class->dispose = swfdec_net_stream_dispose;
+
+ gc_class->mark = swfdec_net_stream_mark;
+}
+
+static void
+swfdec_net_stream_init (SwfdecNetStream *net_stream)
+{
+}
+
/*** AS CODE ***/
SWFDEC_AS_NATIVE (2101, 0, swfdec_net_stream_close)
@@ -87,7 +129,23 @@ void
swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("NetStream.construct (internal)");
+ SwfdecNetStream *stream;
+ SwfdecAsObject *o, *conn;
+
+ SWFDEC_AS_CHECK (0, NULL, "oo", &o, &conn);
+
+ if (!cx->frame->next || !cx->frame->next->construct)
+ return;
+ if (!SWFDEC_IS_RTMP_CONNECTION (conn->relay))
+ return;
+ if (o->movie) {
+ SWFDEC_FIXME ("you managed to call SwfdecNetStream's constructor from a movie. Congrats, but what now?");
+ return;
+ }
+
+ stream = g_object_new (SWFDEC_TYPE_NET_STREAM, "context", cx, NULL);
+ stream->conn = SWFDEC_RTMP_CONNECTION (conn->relay);
+ swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (stream));
}
SWFDEC_AS_NATIVE (2101, 201, swfdec_net_stream_onCreate)
diff --git a/swfdec/swfdec_net_stream.h b/swfdec/swfdec_net_stream.h
new file mode 100644
index 0000000..93fc1fb
--- /dev/null
+++ b/swfdec/swfdec_net_stream.h
@@ -0,0 +1,55 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SWFDEC_NET_STREAM_H_
+#define _SWFDEC_NET_STREAM_H_
+
+#include <swfdec/swfdec_rtmp_connection.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecNetStream SwfdecNetStream;
+typedef struct _SwfdecNetStreamClass SwfdecNetStreamClass;
+
+#define SWFDEC_TYPE_NET_STREAM (swfdec_net_stream_get_type())
+#define SWFDEC_IS_NET_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_NET_STREAM))
+#define SWFDEC_IS_NET_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_NET_STREAM))
+#define SWFDEC_NET_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_NET_STREAM, SwfdecNetStream))
+#define SWFDEC_NET_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_NET_STREAM, SwfdecNetStreamClass))
+#define SWFDEC_NET_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_NET_STREAM, SwfdecNetStreamClass))
+
+struct _SwfdecNetStream {
+ SwfdecAsRelay relay;
+
+ SwfdecRtmpConnection * conn; /* the connection in use */
+ SwfdecRtmpChannel * audio_channel; /* channel used for audio */
+ SwfdecRtmpChannel * video_channel; /* channel used for video */
+ SwfdecRtmpChannel * rpc_channel; /* channel used for RPC */
+};
+
+struct _SwfdecNetStreamClass {
+ SwfdecAsRelayClass relay_class;
+};
+
+GType swfdec_net_stream_get_type (void);
+
+
+G_END_DECLS
+#endif
commit 5fe88d359a69898da4d64df7c01afe1f972ca187
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 3 09:27:15 2008 +0000
g_return_if_fail when _set_relay() is called on a movie object
diff --git a/swfdec/swfdec_as_object.c b/swfdec/swfdec_as_object.c
index 06abd57..003f98a 100644
--- a/swfdec/swfdec_as_object.c
+++ b/swfdec/swfdec_as_object.c
@@ -1879,6 +1879,7 @@ void
swfdec_as_object_set_relay (SwfdecAsObject *object, SwfdecAsRelay *relay)
{
g_return_if_fail (object != NULL);
+ g_return_if_fail (!object->movie);
if (relay) {
g_return_if_fail (SWFDEC_IS_AS_RELAY (relay));
diff --git a/swfdec/swfdec_movie.c b/swfdec/swfdec_movie.c
index 735cf78..b3c0579 100644
--- a/swfdec/swfdec_movie.c
+++ b/swfdec/swfdec_movie.c
@@ -1319,8 +1319,8 @@ swfdec_movie_constructor (GType type, guint n_construct_properties,
/* create AsObject */
o = swfdec_as_object_new_empty (cx);
- o->movie = TRUE;
swfdec_as_object_set_relay (o, SWFDEC_AS_RELAY (movie));
+ o->movie = TRUE;
/* set $version variable */
if (movie->parent == NULL) {
commit f8784d9bc1783f6e5b852308479898f7213a6511
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 3 09:06:07 2008 +0000
bail early if the URL cannot be opened
diff --git a/swfdec/swfdec_rtmp_connection.c b/swfdec/swfdec_rtmp_connection.c
index 7beeec9..2015d86 100644
--- a/swfdec/swfdec_rtmp_connection.c
+++ b/swfdec/swfdec_rtmp_connection.c
@@ -98,6 +98,9 @@ swfdec_rtmp_connection_connect (SwfdecRtmpConnection *conn, const SwfdecURL *url
SWFDEC_FIXME ("handle NULL urls in connect()");
}
+ if (conn->error)
+ return;
+
swfdec_rtmp_connection_register_channel (conn, 0, SWFDEC_TYPE_RTMP_HANDSHAKE_CHANNEL);
swfdec_rtmp_connection_register_channel (conn, 2, SWFDEC_TYPE_RTMP_CONTROL_CHANNEL);
swfdec_rtmp_connection_register_channel (conn, 3, SWFDEC_TYPE_RTMP_RPC_CHANNEL);
commit 922fda58d0e505e95c74473243734fa0f6b319f5
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 2 22:31:58 2008 +0000
revert net stream code into stub state
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index ae46189..201c5b0 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -118,6 +118,7 @@ libswfdec_source_files = \
swfdec_movie_asprops.c \
swfdec_movie_clip_loader.c \
swfdec_net_connection.c \
+ swfdec_net_stream.c \
swfdec_path.c \
swfdec_pattern.c \
swfdec_player.c \
diff --git a/swfdec/swfdec_net_stream.c b/swfdec/swfdec_net_stream.c
index a3ce716..cde9348 100644
--- a/swfdec/swfdec_net_stream.c
+++ b/swfdec/swfdec_net_stream.c
@@ -1,5 +1,5 @@
/* Swfdec
- * Copyright (C) 2007-2008 Benjamin Otte <otte at gnome.org>
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,669 +21,88 @@
#include "config.h"
#endif
-#include <math.h>
-#include "swfdec_net_stream.h"
-#include "swfdec_access.h"
-#include "swfdec_amf.h"
-#include "swfdec_as_frame_internal.h"
#include "swfdec_as_internal.h"
-#include "swfdec_as_strings.h"
-#include "swfdec_audio_flv.h"
-#include "swfdec_cached_video.h"
#include "swfdec_debug.h"
-#include "swfdec_loader_internal.h"
-#include "swfdec_player_internal.h"
-#include "swfdec_renderer_internal.h"
-#include "swfdec_resource.h"
-#include "swfdec_sandbox.h"
-#include "swfdec_stream_target.h"
-#include "swfdec_video_provider.h"
-/* NB: code and level must be rooted gc-strings */
-static void
-swfdec_net_stream_onstatus (SwfdecNetStream *stream, const char *code, const char *level)
-{
- SwfdecAsValue val;
- SwfdecAsObject *object;
- SwfdecAsContext *cx;
-
- cx = swfdec_gc_object_get_context (stream);
- swfdec_sandbox_use (stream->sandbox);
- object = swfdec_as_object_new (cx, SWFDEC_AS_STR_Object, NULL);
- SWFDEC_INFO ("emitting onStatus for %s %s", level, code);
- SWFDEC_AS_VALUE_SET_STRING (&val, code);
- swfdec_as_object_set_variable (object, SWFDEC_AS_STR_code, &val);
- SWFDEC_AS_VALUE_SET_STRING (&val, level);
- swfdec_as_object_set_variable (object, SWFDEC_AS_STR_level, &val);
-
- SWFDEC_AS_VALUE_SET_OBJECT (&val, object);
- if (!swfdec_as_relay_call (SWFDEC_AS_RELAY (stream),
- SWFDEC_AS_STR_onStatus, 1, &val, NULL)) {
- // if it's an error message and the stream object didn't have onStatus
- // handler, call System.onStatus
- if (level == SWFDEC_AS_STR_error) {
- SwfdecAsValue system;
-
- swfdec_as_object_get_variable (cx->global,
- SWFDEC_AS_STR_System, &system);
- if (SWFDEC_AS_VALUE_IS_COMPOSITE (system) &&
- (object = SWFDEC_AS_VALUE_GET_COMPOSITE (system)) != NULL) {
- swfdec_as_object_call (object, SWFDEC_AS_STR_onStatus, 1, &val, NULL);
- }
- }
- }
- swfdec_sandbox_unuse (stream->sandbox);
-}
-
-static void
-swfdec_net_stream_decode_video (SwfdecVideoDecoder *decoder, SwfdecBuffer *buffer)
-{
- if (decoder->codec == SWFDEC_VIDEO_CODEC_VP6 ||
- decoder->codec == SWFDEC_VIDEO_CODEC_VP6_ALPHA) {
- /* FIXME: This is somewhat nasty as we modify values in the decoder
- * directly. I know the current decoders don't mind, but if we expose
- * the decoder API... */
- guint wsub, hsub;
- SwfdecBuffer *tmp;
- if (buffer->length == 0) {
- swfdec_video_decoder_error (decoder, "0-byte VP6 video image buffer?");
- return;
- }
- wsub = *buffer->data;
- hsub = wsub & 0xF;
- wsub >>= 4;
- tmp = swfdec_buffer_new_subbuffer (buffer, 1, buffer->length - 1);
- swfdec_video_decoder_decode (decoder, tmp);
- swfdec_buffer_unref (tmp);
- if (hsub >= decoder->height || wsub >= decoder->width) {
- SWFDEC_ERROR ("can't reduce size by more than available");
- decoder->width = 0;
- decoder->height = 0;
- } else {
- decoder->width -= wsub;
- decoder->height -= hsub;
- }
- } else if (decoder->codec == SWFDEC_VIDEO_CODEC_H264) {
- SwfdecBits bits;
- guint type;
- SwfdecBuffer *data;
- swfdec_bits_init (&bits, buffer);
- type = swfdec_bits_get_u8 (&bits);
- /* composition_time_offset = */ swfdec_bits_get_bu24 (&bits);
- switch (type) {
- case 0:
- data = swfdec_bits_get_buffer (&bits, -1);
- if (data) {
- swfdec_video_decoder_set_codec_data (decoder, data);
- swfdec_buffer_unref (data);
- }
- break;
- case 1:
- data = swfdec_bits_get_buffer (&bits, -1);
- if (data) {
- swfdec_video_decoder_decode (decoder, data);
- } else {
- SWFDEC_ERROR ("no data in H264 buffer?");
- }
- break;
- case 2:
- break;
- default:
- SWFDEC_ERROR ("H264 data type %u not supported", type);
- break;
- }
- } else {
- swfdec_video_decoder_decode (decoder, buffer);
- }
-}
-
-static void swfdec_net_stream_update_playing (SwfdecNetStream *stream);
-static void
-swfdec_net_stream_video_goto (SwfdecNetStream *stream, guint timestamp)
-{
- SwfdecBuffer *buffer;
- guint format;
- cairo_surface_t *old;
- gboolean process_events;
- guint process_events_from;
-
- SWFDEC_LOG ("goto %ums", timestamp);
- process_events = timestamp == stream->next_time;
- process_events_from = MIN (stream->next_time, stream->current_time + 1);
- old = stream->surface;
- if (stream->surface) {
- cairo_surface_destroy (stream->surface);
- stream->surface = NULL;
- }
- if (stream->flvdecoder == NULL)
- return;
- if (stream->flvdecoder->video) {
- buffer = swfdec_flv_decoder_get_video (stream->flvdecoder, timestamp,
- FALSE, &format, &stream->current_time, &stream->next_time);
- } else {
- buffer = NULL;
- }
- if (buffer == NULL) {
- SWFDEC_ERROR ("got no buffer - no video available?");
- } else {
- guint next;
-
- if (stream->decoder != NULL &&
- stream->decoder_time >= stream->current_time) {
- buffer = swfdec_flv_decoder_get_video (stream->flvdecoder,
- stream->current_time, TRUE, &format, &stream->decoder_time,
- &next);
- }
-
- if (stream->decoder == NULL) {
- buffer = swfdec_flv_decoder_get_video (stream->flvdecoder,
- stream->current_time, TRUE, &format, &stream->decoder_time,
- &next);
- stream->decoder = swfdec_video_decoder_new (format);
- } else {
- swfdec_flv_decoder_get_video (stream->flvdecoder,
- stream->decoder_time, FALSE, NULL, NULL, &next);
- if (next != stream->current_time) {
- guint key_time, key_next;
- buffer = swfdec_flv_decoder_get_video (stream->flvdecoder,
- stream->current_time, TRUE, &format, &key_time, &key_next);
- if (key_time > stream->decoder_time) {
- stream->decoder_time = key_time;
- next = key_next;
- } else {
- buffer = swfdec_flv_decoder_get_video (stream->flvdecoder,
- next, FALSE, &format, &stream->decoder_time,
- &next);
- }
- } else {
- buffer = swfdec_flv_decoder_get_video (stream->flvdecoder,
- next, FALSE, &format, &stream->decoder_time,
- &next);
- }
- }
-
- /* the following things hold:
- * buffer: next buffer to decode
- * format: format of that buffer
- * stream->decoder_time: timestamp of buffer to decode
- * stream->decoder: non-null, using stream->format
- */
- for (;;) {
- if (format != swfdec_video_decoder_get_codec (stream->decoder)) {
- g_object_unref (stream->decoder);
- stream->decoder = swfdec_video_decoder_new (format);
- }
- swfdec_net_stream_decode_video (stream->decoder, buffer);
- if (stream->decoder_time >= stream->current_time)
- break;
-
- buffer = swfdec_flv_decoder_get_video (stream->flvdecoder,
- next, FALSE, &format, &stream->decoder_time, &next);
- }
-
- swfdec_video_provider_new_image (SWFDEC_VIDEO_PROVIDER (stream));
- }
- if (stream->next_time <= stream->current_time) {
- if (swfdec_flv_decoder_is_eof (stream->flvdecoder)) {
- swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Play_Stop, SWFDEC_AS_STR_status);
- } else {
- stream->buffering = TRUE;
- swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Empty,
- SWFDEC_AS_STR_status);
- }
- swfdec_net_stream_update_playing (stream);
- }
- if (process_events) {
- while (stream->flvdecoder && process_events_from <= stream->current_time) {
- SwfdecAsValue name, value;
- SwfdecBits bits;
- SwfdecBuffer *event = swfdec_flv_decoder_get_data (stream->flvdecoder, process_events_from, &process_events_from);
- if (!event)
- break;
- SWFDEC_LOG ("processing event from timestamp %u", process_events_from);
- process_events_from++; /* increase so we get the next event next time */
- swfdec_bits_init (&bits, event);
- swfdec_sandbox_use (stream->sandbox);
- if (swfdec_amf_parse (swfdec_gc_object_get_context (stream), &bits, 2,
- SWFDEC_AMF_STRING, &name, SWFDEC_AMF_MIXED_ARRAY, &value) != 2) {
- SWFDEC_ERROR ("could not parse data tag");
- } else {
- swfdec_as_relay_call (SWFDEC_AS_RELAY (stream),
- SWFDEC_AS_VALUE_GET_STRING (name), 1, &value, NULL);
- }
- swfdec_sandbox_unuse (stream->sandbox);
- }
- }
-}
-
-static void
-swfdec_net_stream_timeout (SwfdecTimeout *timeout)
-{
- SwfdecNetStream *stream = SWFDEC_NET_STREAM ((void *) ((guchar *) timeout - G_STRUCT_OFFSET (SwfdecNetStream, timeout)));
- SwfdecTick timestamp;
-
- SWFDEC_LOG ("timeout fired");
- swfdec_net_stream_video_goto (stream, stream->next_time);
- timestamp = stream->timeout.timestamp;
- if (stream->timeout.timestamp == timestamp &&
- stream->timeout.callback) {
- SWFDEC_LOG ("readding timeout");
- stream->timeout.timestamp += SWFDEC_MSECS_TO_TICKS (stream->next_time - stream->current_time);
- swfdec_player_add_timeout (SWFDEC_PLAYER (swfdec_gc_object_get_context (stream)), &stream->timeout);
- }
-}
-
-static void
-swfdec_net_stream_update_playing (SwfdecNetStream *stream)
-{
- SwfdecPlayer *player = SWFDEC_PLAYER (swfdec_gc_object_get_context (stream));
- gboolean should_play;
-
- should_play = stream->playing; /* checks user-set play/pause */
- should_play &= !stream->buffering; /* checks enough data is available */
- should_play &= stream->flvdecoder != NULL; /* checks there even is something to play */
- should_play &= stream->next_time > stream->current_time; /* checks if EOF */
- if (should_play && stream->timeout.callback == NULL) {
- SWFDEC_DEBUG ("starting playback");
- stream->timeout.callback = swfdec_net_stream_timeout;
- stream->timeout.timestamp = player->priv->time + SWFDEC_MSECS_TO_TICKS (stream->next_time - stream->current_time);
- swfdec_player_add_timeout (player, &stream->timeout);
- if (stream->flvdecoder->audio) {
- g_assert (stream->audio == NULL);
- SWFDEC_LOG ("starting audio");
- stream->audio = swfdec_audio_flv_new (player,
- stream->flvdecoder, stream->current_time);
- } else {
- SWFDEC_LOG ("no audio");
- }
- } else if (!should_play && stream->timeout.callback != NULL) {
- if (stream->audio) {
- SWFDEC_LOG ("stopping audio");
- swfdec_audio_remove (stream->audio);
- g_object_unref (stream->audio);
- stream->audio = NULL;
- }
- /* FIXME: timeout might or might not be be added here if
- * timestamp == player->priv->time, but we'll just remove to be sure */
- swfdec_player_remove_timeout (player, &stream->timeout);
- stream->timeout.callback = NULL;
- SWFDEC_DEBUG ("stopping playback");
- }
-}
-
-/*** SWFDEC_STREAM_TARGET interface ***/
-
-static SwfdecPlayer *
-swfdec_net_stream_stream_target_get_player (SwfdecStreamTarget *target)
-{
- return SWFDEC_PLAYER (swfdec_gc_object_get_context (target));
-}
-
-static void
-swfdec_net_stream_stream_target_error (SwfdecStreamTarget *target,
- SwfdecStream *stream)
-{
- SwfdecNetStream *ns = SWFDEC_NET_STREAM (target);
-
- if (ns->flvdecoder == NULL)
- swfdec_net_stream_onstatus (ns, SWFDEC_AS_STR_NetStream_Play_StreamNotFound,
- SWFDEC_AS_STR_error);
-}
-
-static void
-swfdec_net_stream_stream_target_recheck (SwfdecNetStream *stream)
-{
- if (stream->buffering) {
- guint first, last;
- if (swfdec_flv_decoder_get_video_info (stream->flvdecoder, &first, &last)) {
- guint current = MAX (first, stream->current_time);
- if (current + stream->buffer_time <= last) {
- swfdec_net_stream_video_goto (stream, current);
- stream->buffering = FALSE;
- swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Full,
- SWFDEC_AS_STR_status);
- }
- } else {
- SWFDEC_ERROR ("no video stream, how do we update buffering?");
- }
- }
- swfdec_net_stream_update_playing (stream);
-}
-
-static gboolean
-swfdec_net_stream_stream_target_parse (SwfdecStreamTarget *target,
- SwfdecStream *stream)
-{
- SwfdecNetStream *ns = SWFDEC_NET_STREAM (target);
- SwfdecBufferQueue *queue;
- SwfdecStatus status;
-
- if (ns->flvdecoder == NULL) {
- /* FIXME: add mp3 support */
- ns->flvdecoder = g_object_new (SWFDEC_TYPE_FLV_DECODER, NULL);
- g_signal_connect_swapped (ns->flvdecoder, "missing-plugin",
- G_CALLBACK (swfdec_player_add_missing_plugin), swfdec_gc_object_get_context (ns));
- swfdec_net_stream_onstatus (ns, SWFDEC_AS_STR_NetStream_Play_Start,
- SWFDEC_AS_STR_status);
- swfdec_loader_set_data_type (SWFDEC_LOADER (stream), SWFDEC_LOADER_DATA_FLV);
- }
-
- status = SWFDEC_STATUS_OK;
- queue = swfdec_stream_get_queue (stream);
- do {
- SwfdecBuffer *buffer = swfdec_buffer_queue_pull_buffer (queue);
- if (buffer == NULL)
- break;
- status &= ~SWFDEC_STATUS_NEEDBITS;
- status |= swfdec_decoder_parse (SWFDEC_DECODER (ns->flvdecoder), buffer);
- } while ((status & (SWFDEC_STATUS_ERROR | SWFDEC_STATUS_EOF | SWFDEC_STATUS_INIT)) == 0);
-
- if (status & SWFDEC_STATUS_INIT)
- return TRUE;
-
- if (status & SWFDEC_STATUS_IMAGE)
- swfdec_net_stream_stream_target_recheck (ns);
- return FALSE;
-}
-
-static void
-swfdec_net_stream_stream_target_close (SwfdecStreamTarget *target,
- SwfdecStream *stream)
-{
- SwfdecNetStream *ns = SWFDEC_NET_STREAM (target);
- guint first, last;
-
- swfdec_decoder_eof (SWFDEC_DECODER (ns->flvdecoder));
- swfdec_net_stream_onstatus (ns, SWFDEC_AS_STR_NetStream_Buffer_Flush,
- SWFDEC_AS_STR_status);
- if (ns->flvdecoder == NULL)
- return;
- swfdec_net_stream_video_goto (ns, ns->current_time);
- ns->buffering = FALSE;
- if (swfdec_flv_decoder_get_video_info (ns->flvdecoder, &first, &last) &&
- ns->current_time + ns->buffer_time <= last) {
- swfdec_net_stream_onstatus (ns, SWFDEC_AS_STR_NetStream_Buffer_Full,
- SWFDEC_AS_STR_status);
- }
- swfdec_net_stream_stream_target_recheck (ns);
-}
-
-static void
-swfdec_net_stream_stream_target_init (SwfdecStreamTargetInterface *iface)
-{
- iface->get_player = swfdec_net_stream_stream_target_get_player;
- iface->parse = swfdec_net_stream_stream_target_parse;
- iface->close = swfdec_net_stream_stream_target_close;
- iface->error = swfdec_net_stream_stream_target_error;
-}
-
-/*** SWFDEC VIDEO PROVIDER ***/
+/*** AS CODE ***/
-static cairo_surface_t *
-swfdec_net_stream_video_provider_get_image (SwfdecVideoProvider *provider,
- SwfdecRenderer *renderer, guint *width, guint *height)
-{
- SwfdecNetStream *stream = SWFDEC_NET_STREAM (provider);
- SwfdecCachedVideo *cached;
- cairo_surface_t *surface;
-
- cached = SWFDEC_CACHED_VIDEO (swfdec_renderer_get_cache (renderer, stream, NULL, NULL));
- if (cached != NULL && swfdec_cached_video_get_frame (cached) == stream->current_time) {
- swfdec_cached_use (SWFDEC_CACHED (cached));
- swfdec_cached_video_get_size (cached, width, height);
- return swfdec_cached_video_get_surface (cached);
- }
-
- if (stream->decoder == NULL)
- return NULL;
-
- surface = swfdec_video_decoder_get_image (stream->decoder, renderer);
- if (surface == NULL)
- return NULL;
- *width = swfdec_video_decoder_get_width (stream->decoder);
- *height = swfdec_video_decoder_get_height (stream->decoder);
- cached = swfdec_cached_video_new (surface, *width * *height * 4);
- swfdec_cached_video_set_frame (cached, stream->decoder_time);
- swfdec_cached_video_set_size (cached, *width, *height);
- swfdec_renderer_add_cache (renderer, TRUE, stream, SWFDEC_CACHED (cached));
- g_object_unref (cached);
-
- return surface;
-}
-
-static void
-swfdec_net_stream_video_provider_get_size (SwfdecVideoProvider *provider,
- guint *width, guint *height)
-{
- SwfdecNetStream *stream = SWFDEC_NET_STREAM (provider);
-
- if (stream->decoder) {
- *width = swfdec_video_decoder_get_width (stream->decoder);
- *height = swfdec_video_decoder_get_height (stream->decoder);
- } else {
- *width = 0;
- *height = 0;
- }
-}
-
-static void
-swfdec_net_stream_video_provider_init (SwfdecVideoProviderInterface *iface)
-{
- iface->get_image = swfdec_net_stream_video_provider_get_image;
- iface->get_size = swfdec_net_stream_video_provider_get_size;
-}
-
-/*** SWFDEC_NET_STREAM ***/
-
-G_DEFINE_TYPE_WITH_CODE (SwfdecNetStream, swfdec_net_stream, SWFDEC_TYPE_AS_RELAY,
- G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_STREAM_TARGET, swfdec_net_stream_stream_target_init)
- G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_VIDEO_PROVIDER, swfdec_net_stream_video_provider_init))
-
-static void
-swfdec_net_stream_dispose (GObject *object)
-{
- SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
-
- swfdec_net_stream_set_playing (stream, FALSE);
- if (stream->surface) {
- cairo_surface_destroy (stream->surface);
- stream->surface = NULL;
- }
- if (stream->decoder) {
- g_object_unref (stream->decoder);
- stream->decoder = NULL;
- }
- swfdec_net_stream_set_loader (stream, NULL);
- g_assert (stream->movies == NULL);
- g_free (stream->requested_url);
- stream->requested_url = NULL;
-
- G_OBJECT_CLASS (swfdec_net_stream_parent_class)->dispose (object);
-}
-
-static void
-swfdec_net_stream_mark (SwfdecGcObject *object)
-{
- SwfdecNetStream *stream = SWFDEC_NET_STREAM (object);
-
- if (stream->conn)
- swfdec_gc_object_mark (stream->conn);
- if (stream->sandbox)
- swfdec_gc_object_mark (stream->sandbox);
-
- SWFDEC_GC_OBJECT_CLASS (swfdec_net_stream_parent_class)->mark (object);
-}
-
-static void
-swfdec_net_stream_class_init (SwfdecNetStreamClass *klass)
+SWFDEC_AS_NATIVE (2101, 0, swfdec_net_stream_close)
+void
+swfdec_net_stream_close (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
-
- object_class->dispose = swfdec_net_stream_dispose;
-
- gc_class->mark = swfdec_net_stream_mark;
+ SWFDEC_STUB ("NetStream.close");
}
-static void
-swfdec_net_stream_init (SwfdecNetStream *stream)
+SWFDEC_AS_NATIVE (2101, 1, swfdec_net_stream_attachAudio)
+void
+swfdec_net_stream_attachAudio(SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- stream->buffer_time = 100; /* msecs */
+ SWFDEC_STUB ("NetStream.attachAudio");
}
-static void
-swfdec_net_stream_load (SwfdecPlayer *player, gboolean allowed, gpointer streamp)
+SWFDEC_AS_NATIVE (2101, 2, swfdec_net_stream_attachVideo)
+void
+swfdec_net_stream_attachVideo (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SwfdecNetStream *stream = streamp;
- SwfdecLoader *loader;
-
- if (allowed) {
- loader = swfdec_player_load (player, stream->requested_url, NULL);
- swfdec_net_stream_set_loader (stream, loader);
- g_object_unref (loader);
- } else {
- SWFDEC_WARNING ("SECURITY: no access to %s from NetStream",
- stream->requested_url);
- stream->sandbox = NULL;
- }
- g_free (stream->requested_url);
- stream->requested_url = NULL;
+ SWFDEC_STUB ("NetStream.attachVideo");
}
-// When checkPolicyFile is true the YES values in last column must be changed
-// to POLICY
-static const SwfdecAccessMatrix swfdec_net_stream_matrix = {
- { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO },
- { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_YES, SWFDEC_ACCESS_YES },
- { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO },
- { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_YES },
- { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_YES }
-};
-
+SWFDEC_AS_NATIVE (2101, 3, swfdec_net_stream_send)
void
-swfdec_net_stream_set_url (SwfdecNetStream *stream, const char *url_string)
+swfdec_net_stream_send (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SwfdecPlayer *player;
- SwfdecAsContext *cx;
-
- g_return_if_fail (SWFDEC_IS_NET_STREAM (stream));
- g_return_if_fail (url_string != NULL);
-
- cx = swfdec_gc_object_get_context (stream);
- player = SWFDEC_PLAYER (cx);
-
- if (stream->requested_url != NULL) {
- SWFDEC_FIXME ("can't load %s - already loading %s, what now?",
- url_string, stream->requested_url);
- return;
- }
- stream->requested_url = g_strdup (url_string);
- stream->sandbox = swfdec_sandbox_get (player);
-
- swfdec_player_allow_by_matrix (player, stream->sandbox, url_string,
- swfdec_net_stream_matrix, swfdec_net_stream_load, stream);
+ SWFDEC_STUB ("NetStream.send");
}
+SWFDEC_AS_NATIVE (2101, 4, swfdec_net_stream_setBufferTime)
void
-swfdec_net_stream_set_loader (SwfdecNetStream *stream, SwfdecLoader *loader)
+swfdec_net_stream_setBufferTime (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- g_return_if_fail (SWFDEC_IS_NET_STREAM (stream));
- g_return_if_fail (loader == NULL || SWFDEC_IS_SANDBOX (stream->sandbox));
- g_return_if_fail (loader == NULL || SWFDEC_IS_LOADER (loader));
-
- if (stream->loader) {
- SwfdecStream *lstream = SWFDEC_STREAM (stream->loader);
- swfdec_stream_ensure_closed (lstream);
- swfdec_stream_set_target (lstream, NULL);
- g_object_unref (lstream);
- }
- if (stream->flvdecoder) {
- g_signal_handlers_disconnect_by_func (stream->flvdecoder,
- swfdec_player_add_missing_plugin, swfdec_gc_object_get_context (stream));
- g_object_unref (stream->flvdecoder);
- stream->flvdecoder = NULL;
- }
- stream->loader = loader;
- stream->buffering = TRUE;
- if (loader) {
- g_object_ref (loader);
- swfdec_stream_set_target (SWFDEC_STREAM (loader), SWFDEC_STREAM_TARGET (stream));
- }
- swfdec_net_stream_set_playing (stream, TRUE);
+ SWFDEC_STUB ("NetStream.setBufferTime");
}
+SWFDEC_AS_NATIVE (2101, 5, swfdec_net_stream_get_checkPolicyFile)
void
-swfdec_net_stream_set_playing (SwfdecNetStream *stream, gboolean playing)
+swfdec_net_stream_get_checkPolicyFile (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- g_return_if_fail (SWFDEC_IS_NET_STREAM (stream));
-
- stream->playing = playing;
-
- swfdec_net_stream_update_playing (stream);
+ SWFDEC_STUB ("NetStream.checkPolicyFile (get)");
}
-gboolean
-swfdec_net_stream_get_playing (SwfdecNetStream *stream)
+SWFDEC_AS_NATIVE (2101, 6, swfdec_net_stream_set_checkPolicyFile)
+void
+swfdec_net_stream_set_checkPolicyFile (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- g_return_val_if_fail (SWFDEC_IS_NET_STREAM (stream), FALSE);
-
- return stream->playing;
+ SWFDEC_STUB ("NetStream.checkPolicyFile (set)");
}
+SWFDEC_AS_NATIVE (2101, 200, swfdec_net_stream_construct)
void
-swfdec_net_stream_set_buffer_time (SwfdecNetStream *stream, double secs)
+swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- g_return_if_fail (SWFDEC_IS_NET_STREAM (stream));
-
- /* FIXME: is this correct? */
- if (secs <= 0)
- return;
-
- stream->buffer_time = secs * 1000;
+ SWFDEC_STUB ("NetStream.construct (internal)");
}
-double
-swfdec_net_stream_get_buffer_time (SwfdecNetStream *stream)
+SWFDEC_AS_NATIVE (2101, 201, swfdec_net_stream_onCreate)
+void
+swfdec_net_stream_onCreate (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- g_return_val_if_fail (SWFDEC_IS_NET_STREAM (stream), 0.1);
-
- return (double) stream->buffer_time / 1000.0;
+ SWFDEC_STUB ("NetStream.onCreate (internal)");
}
+SWFDEC_AS_NATIVE (2101, 202, swfdec_net_stream_send_connection)
void
-swfdec_net_stream_seek (SwfdecNetStream *stream, double secs)
+swfdec_net_stream_send_connection (SwfdecAsContext *cx, SwfdecAsObject *object,
+ guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- guint first, last, msecs;
-
- g_return_if_fail (SWFDEC_IS_NET_STREAM (stream));
-
- if (stream->flvdecoder == NULL)
- return;
- if (!isfinite (secs) || secs < 0) {
- SWFDEC_ERROR ("seeking to %g doesn't work", secs);
- return;
- }
- if (!swfdec_flv_decoder_get_video_info (stream->flvdecoder, &first, &last)) {
- SWFDEC_ERROR ("FIXME: implement seeking in audio only NetStream");
- return;
- }
- msecs = secs * 1000;
- msecs += first;
- if (msecs > last)
- msecs = last;
- swfdec_flv_decoder_get_video (stream->flvdecoder, msecs, TRUE, NULL, &msecs, NULL);
- swfdec_net_stream_video_goto (stream, msecs);
- /* FIXME: this needs to be implemented correctly, but requires changes to audio handling:
- * - creating a new audio stream will cause attachAudio scripts to lose information
- * - implementing seek on audio stream requires a SwfdecAudio::changed signal so audio
- * backends can react correctly.
- */
- if (stream->audio) {
- SWFDEC_WARNING ("FIXME: restarting audio after seek");
- swfdec_audio_remove (stream->audio);
- g_object_unref (stream->audio);
- stream->audio = swfdec_audio_flv_new (SWFDEC_PLAYER (swfdec_gc_object_get_context (stream)),
- stream->flvdecoder, stream->current_time);
- }
+ SWFDEC_STUB ("NetStream.send_connection (internal)");
}
diff --git a/swfdec/swfdec_net_stream.h b/swfdec/swfdec_net_stream.h
deleted file mode 100644
index 078b9e9..0000000
--- a/swfdec/swfdec_net_stream.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Swfdec
- * Copyright (C) 2007-2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _SWFDEC_NET_STREAM_H_
-#define _SWFDEC_NET_STREAM_H_
-
-#include <swfdec/swfdec.h>
-#include <swfdec/swfdec_as_relay.h>
-#include <swfdec/swfdec_net_connection.h>
-#include <swfdec/swfdec_flv_decoder.h>
-#include <swfdec/swfdec_player_internal.h>
-#include <swfdec/swfdec_sandbox.h>
-#include <swfdec/swfdec_video_decoder.h>
-#include <swfdec/swfdec_video_movie.h>
-
-G_BEGIN_DECLS
-
-typedef struct _SwfdecNetStream SwfdecNetStream;
-typedef struct _SwfdecNetStreamClass SwfdecNetStreamClass;
-
-#define SWFDEC_TYPE_NET_STREAM (swfdec_net_stream_get_type())
-#define SWFDEC_IS_NET_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_NET_STREAM))
-#define SWFDEC_IS_NET_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_NET_STREAM))
-#define SWFDEC_NET_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_NET_STREAM, SwfdecNetStream))
-#define SWFDEC_NET_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_NET_STREAM, SwfdecNetStreamClass))
-#define SWFDEC_NET_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_NET_STREAM, SwfdecNetStreamClass))
-
-struct _SwfdecNetStream
-{
- SwfdecAsRelay relay;
-
- SwfdecNetConnection * conn; /* connection used for opening streams */
- char * requested_url; /* URL we have requested that isn't loaded yet */
- SwfdecLoader * loader; /* input stream */
- SwfdecSandbox * sandbox; /* sandbox to emit events in */
- SwfdecFlvDecoder * flvdecoder; /* flv decoder */
- gboolean playing; /* TRUE if this stream is playing */
- gboolean buffering; /* TRUE if we're waiting for more input data */
- gboolean error; /* in error */
-
- /* properties */
- guint buffer_time; /* buffering time in msecs */
-
- /* video decoding */
- guint current_time; /* current playback timestamp */
- guint next_time; /* next video image at this timestamp */
- SwfdecVideoDecoder * decoder; /* decoder used for decoding */
- guint decoder_time; /* last timestamp the decoder decoded */
- cairo_surface_t * surface; /* current image */
- SwfdecTimeout timeout; /* timeout to advance to */
- GList * movies; /* movies we're connected to */
-
- /* audio */
- SwfdecAudio * audio; /* audio stream or NULL when not playing */
-};
-
-struct _SwfdecNetStreamClass
-{
- SwfdecAsRelayClass relay_class;
-};
-
-GType swfdec_net_stream_get_type (void);
-
-void swfdec_net_stream_set_url (SwfdecNetStream * stream,
- const char * url);
-void swfdec_net_stream_set_loader (SwfdecNetStream * stream,
- SwfdecLoader * loader);
-void swfdec_net_stream_set_playing (SwfdecNetStream * stream,
- gboolean playing);
-gboolean swfdec_net_stream_get_playing (SwfdecNetStream * stream);
-void swfdec_net_stream_set_buffer_time (SwfdecNetStream * stream,
- double secs);
-double swfdec_net_stream_get_buffer_time (SwfdecNetStream * stream);
-void swfdec_net_stream_seek (SwfdecNetStream * stream,
- double secs);
-
-
-G_END_DECLS
-#endif
diff --git a/swfdec/swfdec_net_stream_as.c b/swfdec/swfdec_net_stream_as.c
deleted file mode 100644
index 9167430..0000000
--- a/swfdec/swfdec_net_stream_as.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/* Swfdec
- * Copyright (C) 2007-2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "swfdec_net_stream.h"
-#include "swfdec_as_context.h"
-#include "swfdec_as_internal.h"
-#include "swfdec_as_native_function.h"
-#include "swfdec_as_strings.h"
-#include "swfdec_debug.h"
-#include "swfdec_internal.h"
-#include "swfdec_player_internal.h"
-#include "swfdec_sandbox.h"
-
-SWFDEC_AS_NATIVE (2101, 0, swfdec_net_stream_close)
-void
-swfdec_net_stream_close (SwfdecAsContext *cx, SwfdecAsObject *object,
- guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SwfdecNetStream *stream;
-
- SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
-
- swfdec_net_stream_set_loader (stream, NULL);
- swfdec_net_stream_set_playing (stream, TRUE);
-}
-
-static void
-swfdec_net_stream_play (SwfdecAsContext *cx, SwfdecAsObject *object,
- guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SwfdecNetStream *stream;
- const char *url;
-
- SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "s", &url);
-
- swfdec_net_stream_set_url (stream, url);
- swfdec_net_stream_set_playing (stream, TRUE);
-}
-
-static void
-swfdec_net_stream_pause (SwfdecAsContext *cx, SwfdecAsObject *object,
- guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SwfdecNetStream *stream;
- gboolean playing;
-
- SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
-
- if (argc == 0) {
- playing = !swfdec_net_stream_get_playing (stream);
- } else {
- playing = !swfdec_as_value_to_boolean (cx, argv[0]);
- }
- SWFDEC_LOG ("%s stream %p", playing ? "playing" : "pausing", stream);
- swfdec_net_stream_set_playing (stream, playing);
-}
-
-SWFDEC_AS_NATIVE (2101, 1, swfdec_net_stream_attachAudio)
-void
-swfdec_net_stream_attachAudio (SwfdecAsContext *cx, SwfdecAsObject *obj,
- guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SWFDEC_STUB ("NetStream.attachAudio");
-}
-
-SWFDEC_AS_NATIVE (2101, 2, swfdec_net_stream_attachVideo)
-void
-swfdec_net_stream_attachVideo (SwfdecAsContext *cx, SwfdecAsObject *obj,
- guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SWFDEC_STUB ("NetStream.attachVideo");
-}
-
-SWFDEC_AS_NATIVE (2101, 3, swfdec_net_stream_send)
-void
-swfdec_net_stream_send (SwfdecAsContext *cx, SwfdecAsObject *obj, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SWFDEC_STUB ("NetStream.send");
-}
-
-SWFDEC_AS_NATIVE (2101, 4, swfdec_net_stream_setBufferTime)
-void
-swfdec_net_stream_setBufferTime (SwfdecAsContext *cx, SwfdecAsObject *object,
- guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SwfdecNetStream *stream;
- double d;
-
- SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "n", &d);
-
- swfdec_net_stream_set_buffer_time (stream, d);
-}
-
-SWFDEC_AS_NATIVE (2101, 5, swfdec_net_stream_get_checkPolicyFile)
-void
-swfdec_net_stream_get_checkPolicyFile (SwfdecAsContext *cx,
- SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
- SwfdecAsValue *rval)
-{
- SWFDEC_STUB ("NetStream.checkPolicyFile (get)");
-}
-
-SWFDEC_AS_NATIVE (2101, 6, swfdec_net_stream_set_checkPolicyFile)
-void
-swfdec_net_stream_set_checkPolicyFile (SwfdecAsContext *cx,
- SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
- SwfdecAsValue *rval)
-{
- SWFDEC_STUB ("NetStream.checkPolicyFile (set)");
-}
-
-static void
-swfdec_net_stream_do_seek (SwfdecAsContext *cx, SwfdecAsObject *object,
- guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SwfdecNetStream *stream;
- SwfdecSandbox *cur;
- double d;
-
- SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "n", &d);
-
- cur = swfdec_sandbox_get (SWFDEC_PLAYER (cx));
- swfdec_sandbox_unuse (cur);
- /* FIXME: perform security check if seeking is allowed here? */
- swfdec_net_stream_seek (stream, d);
- swfdec_sandbox_use (cur);
-}
-
-static void
-swfdec_net_stream_get_time (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SwfdecNetStream *stream;
- guint msecs;
-
- SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
-
- if (stream->flvdecoder == NULL ||
- !swfdec_flv_decoder_get_video_info (stream->flvdecoder, &msecs, NULL)) {
- *ret = swfdec_as_value_from_integer (cx, 0);
- } else {
- if (msecs >= stream->current_time)
- msecs = 0;
- else
- msecs = stream->current_time - msecs;
- *ret = swfdec_as_value_from_number (cx, msecs / 1000.);
- }
-}
-
-static void
-swfdec_net_stream_get_bytesLoaded (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SwfdecNetStream *stream;
-
- SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
-
- if (stream->loader == NULL)
- *ret = swfdec_as_value_from_integer (cx, 0);
- else
- *ret = swfdec_as_value_from_number (cx, swfdec_loader_get_loaded (stream->loader));
-}
-
-static void
-swfdec_net_stream_get_bytesTotal (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SwfdecNetStream *stream;
- glong bytes;
-
- SWFDEC_AS_CHECK (SWFDEC_TYPE_NET_STREAM, &stream, "");
-
- if (stream->loader == NULL) {
- bytes = 0;
- } else {
- bytes = swfdec_loader_get_size (stream->loader);
- if (bytes < 0)
- bytes = swfdec_loader_get_loaded (stream->loader);
- }
- *ret = swfdec_as_value_from_number (cx, bytes);
-}
-
-static void
-swfdec_net_stream_get_bufferLength (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SWFDEC_STUB ("Netstream.bufferLength (get)");
-}
-
-static void
-swfdec_net_stream_get_bufferTime (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SWFDEC_STUB ("Netstream.bufferTime (get)");
-}
-
-static void
-swfdec_net_stream_get_audiocodec (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SWFDEC_STUB ("Netstream.audiocodec (get)");
-}
-
-static void
-swfdec_net_stream_get_currentFps (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SWFDEC_STUB ("Netstream.currentFps (get)");
-}
-
-static void
-swfdec_net_stream_get_decodedFrames (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SWFDEC_STUB ("Netstream.decodedFrames (get)");
-}
-
-static void
-swfdec_net_stream_get_liveDelay (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SWFDEC_STUB ("Netstream.liveDelay (get)");
-}
-
-static void
-swfdec_net_stream_get_videoCodec (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- SWFDEC_STUB ("Netstream.videoCodec (get)");
-}
-
-SWFDEC_AS_NATIVE (2101, 200, swfdec_net_stream_setup)
-void
-swfdec_net_stream_setup (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
- SwfdecAsValue *argv, SwfdecAsValue *ret)
-{
- if (object == NULL)
- return;
-
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_time,
- swfdec_net_stream_get_time, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_bytesLoaded,
- swfdec_net_stream_get_bytesLoaded, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_bytesTotal,
- swfdec_net_stream_get_bytesTotal, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_bufferLength,
- swfdec_net_stream_get_bufferLength, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_bufferTime,
- swfdec_net_stream_get_bufferTime, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_audiocodec,
- swfdec_net_stream_get_audiocodec, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_currentFps,
- swfdec_net_stream_get_currentFps, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_decodedFrames,
- swfdec_net_stream_get_decodedFrames, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_liveDelay,
- swfdec_net_stream_get_liveDelay, NULL);
- swfdec_as_object_add_native_variable (object, SWFDEC_AS_STR_videoCodec,
- swfdec_net_stream_get_videoCodec, NULL);
-}
-
-static void
-swfdec_net_stream_construct (SwfdecAsContext *cx, SwfdecAsObject *obj, guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
-{
- SwfdecNetStream *stream;
- SwfdecNetConnection *conn;
-
- if (!swfdec_as_context_is_constructing (cx)) {
- SWFDEC_FIXME ("What do we do if not constructing?");
- return;
- }
- stream = g_object_new (SWFDEC_TYPE_NET_STREAM, "context", cx, NULL);
- swfdec_as_object_set_relay (obj, SWFDEC_AS_RELAY (stream));
-
- swfdec_net_stream_setup (cx, obj, 0, NULL, rval);
- if (argc == 0 ||
- !SWFDEC_AS_VALUE_IS_OBJECT (argv[0]) ||
- !SWFDEC_IS_NET_CONNECTION ((conn = (SwfdecNetConnection *) SWFDEC_AS_VALUE_GET_OBJECT (argv[0])))) {
- SWFDEC_WARNING ("no connection passed to NetStream ()");
- return;
- }
- stream->conn = conn;
- SWFDEC_AS_VALUE_SET_OBJECT (rval, obj);
-}
-
-void
-swfdec_net_stream_init_context (SwfdecPlayer *player)
-{
- SwfdecAsContext *context;
- SwfdecAsObject *stream, *proto;
- SwfdecAsValue val;
-
- g_return_if_fail (SWFDEC_IS_PLAYER (player));
-
- context = SWFDEC_AS_CONTEXT (player);
- proto = swfdec_as_object_new_empty (context);
- stream = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (
- swfdec_as_object_add_function (context->global,
- SWFDEC_AS_STR_NetStream, swfdec_net_stream_construct)));
- /* set the right properties on the NetStream.prototype object */
- swfdec_as_object_add_function (proto, SWFDEC_AS_STR_pause, swfdec_net_stream_pause);
- swfdec_as_object_add_function (proto, SWFDEC_AS_STR_play, swfdec_net_stream_play);
- swfdec_as_object_add_function (proto, SWFDEC_AS_STR_seek, swfdec_net_stream_do_seek);
- SWFDEC_AS_VALUE_SET_OBJECT (&val, stream);
- swfdec_as_object_set_variable_and_flags (proto, SWFDEC_AS_STR_constructor,
- &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
- swfdec_as_object_get_variable (context->global, SWFDEC_AS_STR_Object, &val);
- if (SWFDEC_AS_VALUE_IS_OBJECT (val)) {
- swfdec_as_object_get_variable (SWFDEC_AS_VALUE_GET_OBJECT (val),
- SWFDEC_AS_STR_prototype, &val);
- swfdec_as_object_set_variable_and_flags (proto, SWFDEC_AS_STR___proto__, &val,
- SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
- SWFDEC_AS_VALUE_SET_OBJECT (&val, proto);
- swfdec_as_object_set_variable_and_flags (stream, SWFDEC_AS_STR_prototype, &val,
- SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
- }
-}
-
commit b00d9122760959e4391641ce10a800d09cb0de04
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Dec 2 22:31:44 2008 +0000
fix NetStream constructor to actually work
diff --git a/swfdec/swfdec_initialize.as b/swfdec/swfdec_initialize.as
index c2e9bda..f5664b7 100644
--- a/swfdec/swfdec_initialize.as
+++ b/swfdec/swfdec_initialize.as
@@ -128,17 +128,17 @@ ASSetPropFlags (NetConnection.prototype, null, 3);
/*** NetStream ***/
-function NetStream (conn) {
- var f = ASnative(2101, 200);
+NetStream = function (conn) {
+ var f = ASnative (2101, 200);
f (this, conn);
conn.call ("createStream", { onResult: function (id) {
- var f = ASnative(2101, 201);
+ var f = ASnative (2101, 201);
f (this.stream, id);
}, stream: this });
};
NetStream.prototype.publish = function (name, type) {
- var f = ASnative(2101, 202);
+ var f = ASnative (2101, 202);
if (arguments.length == 1) {
f (this, "publish", null, name);
} else {
@@ -147,12 +147,12 @@ NetStream.prototype.publish = function (name, type) {
};
NetStream.prototype.pause = function (flag) {
- var f = ASnative(2101, 202);
+ var f = ASnative (2101, 202);
f (this, "pause", null, flag, this.time * 1000);
};
NetStream.prototype.play = function (name, start, len, reset) {
- f = ASnative(2101, 202);
+ f = ASnative (2101, 202);
switch (arguments.length) {
case 1:
f (this, "play", null, name);
@@ -170,17 +170,17 @@ NetStream.prototype.play = function (name, start, len, reset) {
};
NetStream.prototype.receiveAudio = function (flag) {
- var f = ASnative(2101, 202);
+ var f = ASnative (2101, 202);
f (this, "receiveAudio", null, flag);
};
NetStream.prototype.receiveVideo = function (flag) {
- var f = ASnative(2101, 202);
+ var f = ASnative (2101, 202);
f (this, "receiveVideo", null, flag);
};
NetStream.prototype.seek = function (offset) {
- var f = ASnative(2101, 202);
+ var f = ASnative (2101, 202);
f (this, "seek", null, offset * 1000);
};
diff --git a/swfdec/swfdec_initialize.h b/swfdec/swfdec_initialize.h
index bcc02a8..265c05a 100644
--- a/swfdec/swfdec_initialize.h
+++ b/swfdec/swfdec_initialize.h
@@ -49,10 +49,10 @@ static const unsigned char swfdec_initialize[] = {
0x61, 0x64, 0x65, 0x72, 0x00, 0x63, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72,
0x6F, 0x78, 0x79, 0x54, 0x79, 0x70, 0x65, 0x00, 0x70, 0x72, 0x6F, 0x78, 0x79, 0x54, 0x79, 0x70,
0x65, 0x00, 0x6E, 0x6F, 0x6E, 0x65, 0x00, 0x75, 0x73, 0x69, 0x6E, 0x67, 0x54, 0x4C, 0x53, 0x00,
- 0x66, 0x00, 0x63, 0x6F, 0x6E, 0x6E, 0x00, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72,
- 0x65, 0x61, 0x6D, 0x00, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x00, 0x69, 0x64, 0x00, 0x6F, 0x6E,
- 0x52, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x00, 0x63, 0x61, 0x6C, 0x6C, 0x00, 0x4E, 0x65, 0x74, 0x53,
- 0x74, 0x72, 0x65, 0x61, 0x6D, 0x00, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x00, 0x61, 0x72,
+ 0x4E, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x00, 0x66, 0x00, 0x63, 0x6F, 0x6E, 0x6E,
+ 0x00, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x00, 0x73, 0x74,
+ 0x72, 0x65, 0x61, 0x6D, 0x00, 0x69, 0x64, 0x00, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x75, 0x6C, 0x74,
+ 0x00, 0x63, 0x61, 0x6C, 0x6C, 0x00, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x00, 0x61, 0x72,
0x67, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x00, 0x74, 0x79, 0x70, 0x65, 0x00, 0x70, 0x61, 0x75,
0x73, 0x65, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x00, 0x74, 0x69, 0x6D, 0x65, 0x00, 0x70, 0x6C, 0x61,
0x79, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x6C, 0x65, 0x6E, 0x00, 0x72, 0x65, 0x73, 0x65,
@@ -536,1877 +536,1877 @@ static const unsigned char swfdec_initialize[] = {
0x74, 0x54, 0x69, 0x6D, 0x65, 0x6F, 0x75, 0x74, 0x00, 0x63, 0x6C, 0x65, 0x61, 0x72, 0x54, 0x69,
0x6D, 0x65, 0x6F, 0x75, 0x74, 0x00, 0x73, 0x68, 0x6F, 0x77, 0x52, 0x65, 0x64, 0x72, 0x61, 0x77,
0x52, 0x65, 0x67, 0x69, 0x6F, 0x6E, 0x73, 0x00, 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x75, 0x70,
- 0x64, 0x61, 0x74, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6E, 0x74, 0x00, 0x9B,
- 0x13, 0x00, 0x4E, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x00, 0x01, 0x00, 0x63, 0x6F,
- 0x6E, 0x6E, 0x00, 0x9B, 0x00, 0x96, 0x13, 0x00, 0x08, 0x43, 0x07, 0xC8, 0x00, 0x00, 0x00, 0x07,
- 0x35, 0x08, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x3C, 0x96, 0x02, 0x00,
- 0x08, 0x44, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x0B, 0x1C, 0x96, 0x07, 0x00, 0x07, 0x02, 0x00, 0x00,
- 0x00, 0x08, 0x43, 0x3D, 0x17, 0x96, 0x02, 0x00, 0x08, 0x48, 0x9B, 0x08, 0x00, 0x00, 0x01, 0x00,
- 0x69, 0x64, 0x00, 0x36, 0x00, 0x96, 0x13, 0x00, 0x08, 0x43, 0x07, 0xC9, 0x00, 0x00, 0x00, 0x07,
- 0x35, 0x08, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x3C, 0x96, 0x02, 0x00,
- 0x08, 0x47, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x0B, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x46, 0x4E, 0x96,
- 0x07, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x43, 0x3D, 0x17, 0x96, 0x04, 0x00, 0x08, 0x46,
- 0x08, 0x0B, 0x1C, 0x96, 0x05, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x43, 0x96, 0x09, 0x00, 0x08,
- 0x45, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x44, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x49, 0x52, 0x17,
- 0x96, 0x13, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07,
- 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x1D, 0x96, 0x13, 0x00, 0x08, 0x02, 0x07, 0x00, 0x00,
- 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x1D,
- 0x96, 0x13, 0x00, 0x08, 0x03, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x07,
- 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x1D, 0x96, 0x07, 0x00, 0x08, 0x04, 0x07, 0x00, 0x00,
- 0x00, 0x00, 0x43, 0x1D, 0x96, 0x02, 0x00, 0x08, 0x05, 0x1C, 0x96, 0x13, 0x00, 0x08, 0x06, 0x07,
- 0x08, 0x00, 0x00, 0x00, 0x07, 0x65, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01,
- 0x3D, 0x4F, 0x96, 0x08, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x02, 0x08, 0x05, 0x1C, 0x96, 0x07,
- 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x3D, 0x17, 0x96, 0x0E, 0x00, 0x07, 0x80, 0x00,
- 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x08, 0x05, 0x1C, 0x96, 0x07, 0x00, 0x07,
- 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x3D, 0x17, 0x96, 0x02, 0x00, 0x08, 0x08, 0x9B, 0x09, 0x00,
- 0x00, 0x01, 0x00, 0x6D, 0x73, 0x67, 0x00, 0x23, 0x00, 0x96, 0x02, 0x00, 0x08, 0x09, 0x1C, 0x44,
- 0x96, 0x02, 0x00, 0x08, 0x0A, 0x49, 0x12, 0x12, 0x9D, 0x02, 0x00, 0x0F, 0x00, 0x96, 0x02, 0x00,
- 0x08, 0x0B, 0x1C, 0x96, 0x04, 0x00, 0x08, 0x0C, 0x08, 0x09, 0x1C, 0x4F, 0x1D, 0x96, 0x02, 0x00,
- 0x08, 0x08, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x0D, 0x4E, 0x96, 0x04, 0x00, 0x08, 0x0E, 0x08, 0x08,
- 0x1C, 0x96, 0x02, 0x00, 0x08, 0x0D, 0x4E, 0x96, 0x04, 0x00, 0x08, 0x0C, 0x08, 0x08, 0x87, 0x01,
- 0x00, 0x00, 0x4F, 0x96, 0x02, 0x00, 0x04, 0x00, 0x4F, 0x96, 0x02, 0x00, 0x08, 0x08, 0x1C, 0x96,
- 0x02, 0x00, 0x08, 0x0D, 0x4E, 0x96, 0x02, 0x00, 0x08, 0x0F, 0x9B, 0x05, 0x00, 0x00, 0x00, 0x00,
- 0x0D, 0x00, 0x96, 0x02, 0x00, 0x08, 0x0B, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x0C, 0x4E, 0x3E, 0x4F,
- 0x96, 0x02, 0x00, 0x08, 0x10, 0x9B, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x96, 0x02,
- 0x00, 0x08, 0x10, 0x1C, 0x96, 0x13, 0x00, 0x08, 0x11, 0x07, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x65,
- 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x4F, 0x96, 0x02, 0x00, 0x08,
- 0x10, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x12, 0x9B, 0x07, 0x00, 0x00, 0x01, 0x00, 0x78, 0x00, 0x3C,
- 0x00, 0x96, 0x02, 0x00, 0x08, 0x13, 0x1C, 0x96, 0x07, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x08,
- 0x0B, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x14, 0x52, 0x17, 0x96, 0x02, 0x00, 0x08, 0x13, 0x1C, 0x96,
- 0x07, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x08, 0x0B, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x15, 0x4E,
- 0x96, 0x02, 0x00, 0x08, 0x16, 0x52, 0x17, 0x96, 0x02, 0x00, 0x05, 0x01, 0x3E, 0x4F, 0x96, 0x02,
- 0x00, 0x08, 0x10, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x14, 0x9B, 0x07, 0x00, 0x00, 0x01, 0x00, 0x78,
- 0x00, 0x8A, 0x00, 0x96, 0x04, 0x00, 0x08, 0x17, 0x08, 0x0B, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x15,
- 0x4E, 0x3C, 0x96, 0x02, 0x00, 0x08, 0x18, 0x41, 0x96, 0x07, 0x00, 0x08, 0x18, 0x07, 0x00, 0x00,
- 0x00, 0x00, 0x3C, 0x96, 0x02, 0x00, 0x08, 0x18, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x17, 0x1C, 0x96,
- 0x02, 0x00, 0x08, 0x19, 0x4E, 0x48, 0x12, 0x9D, 0x02, 0x00, 0x4B, 0x00, 0x96, 0x02, 0x00, 0x08,
- 0x17, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x18, 0x1C, 0x4E, 0x96, 0x02, 0x00, 0x08, 0x13, 0x1C, 0x49,
- 0x12, 0x9D, 0x02, 0x00, 0x23, 0x00, 0x96, 0x07, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x08, 0x18,
- 0x1C, 0x96, 0x07, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x17, 0x1C, 0x96, 0x02, 0x00, 0x08,
- 0x1A, 0x52, 0x17, 0x96, 0x02, 0x00, 0x05, 0x01, 0x3E, 0x96, 0x02, 0x00, 0x08, 0x18, 0x4C, 0x1C,
- 0x50, 0x1D, 0x99, 0x02, 0x00, 0x9C, 0xFF, 0x96, 0x02, 0x00, 0x05, 0x00, 0x3E, 0x4F, 0x96, 0x02,
- 0x00, 0x08, 0x10, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x1B, 0x9B, 0x07, 0x00, 0x00, 0x01, 0x00, 0x6F,
- 0x00, 0x73, 0x00, 0x96, 0x02, 0x00, 0x08, 0x1C, 0x1C, 0x96, 0x13, 0x00, 0x08, 0x11, 0x07, 0x0C,
+ 0x64, 0x61, 0x74, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6E, 0x74, 0x00, 0x96,
+ 0x13, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07, 0x02,
+ 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x1D, 0x96, 0x13, 0x00, 0x08, 0x02, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x1D, 0x96,
+ 0x13, 0x00, 0x08, 0x03, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x07, 0x02,
+ 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x1D, 0x96, 0x07, 0x00, 0x08, 0x04, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x43, 0x1D, 0x96, 0x02, 0x00, 0x08, 0x05, 0x1C, 0x96, 0x13, 0x00, 0x08, 0x06, 0x07, 0x08,
0x00, 0x00, 0x00, 0x07, 0x65, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D,
- 0x4F, 0x96, 0x02, 0x00, 0x08, 0x1C, 0x1C, 0x96, 0x04, 0x00, 0x08, 0x12, 0x08, 0x10, 0x1C, 0x96,
- 0x02, 0x00, 0x08, 0x12, 0x4E, 0x4F, 0x96, 0x02, 0x00, 0x08, 0x1C, 0x1C, 0x96, 0x04, 0x00, 0x08,
- 0x14, 0x08, 0x10, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x14, 0x4E, 0x4F, 0x96, 0x02, 0x00, 0x08, 0x1C,
- 0x1C, 0x96, 0x07, 0x00, 0x08, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4F, 0x96, 0x09, 0x00,
- 0x07, 0x83, 0x00, 0x00, 0x00, 0x08, 0x1D, 0x08, 0x1C, 0x1C, 0x96, 0x07, 0x00, 0x07, 0x03, 0x00,
- 0x00, 0x00, 0x08, 0x00, 0x3D, 0x17, 0x4F, 0x96, 0x8C, 0x00, 0x08, 0x1E, 0x08, 0x1F, 0x07, 0x12,
- 0x00, 0x00, 0x00, 0x08, 0x20, 0x07, 0x08, 0x00, 0x00, 0x00, 0x08, 0x21, 0x07, 0x14, 0x00, 0x00,
- 0x00, 0x08, 0x22, 0x07, 0x11, 0x00, 0x00, 0x00, 0x08, 0x23, 0x07, 0x2E, 0x00, 0x00, 0x00, 0x08,
- 0x24, 0x07, 0x28, 0x00, 0x00, 0x00, 0x08, 0x25, 0x07, 0x23, 0x00, 0x00, 0x00, 0x08, 0x26, 0x07,
- 0x0D, 0x00, 0x00, 0x00, 0x08, 0x27, 0x07, 0x1B, 0x00, 0x00, 0x00, 0x08, 0x28, 0x07, 0x24, 0x00,
- 0x00, 0x00, 0x08, 0x29, 0x07, 0x2D, 0x00, 0x00, 0x00, 0x08, 0x2A, 0x07, 0x25, 0x00, 0x00, 0x00,
- 0x08, 0x2B, 0x07, 0x22, 0x00, 0x00, 0x00, 0x08, 0x2C, 0x07, 0x21, 0x00, 0x00, 0x00, 0x08, 0x2D,
- 0x07, 0x27, 0x00, 0x00, 0x00, 0x08, 0x2E, 0x07, 0x10, 0x00, 0x00, 0x00, 0x08, 0x2F, 0x07, 0x20,
- 0x00, 0x00, 0x00, 0x08, 0x30, 0x07, 0x09, 0x00, 0x00, 0x00, 0x08, 0x31, 0x07, 0x26, 0x00, 0x00,
- 0x00, 0x07, 0x13, 0x00, 0x00, 0x00, 0x43, 0x1D, 0x96, 0x09, 0x00, 0x08, 0x32, 0x07, 0x20, 0x03,
- 0x00, 0x00, 0x08, 0x1E, 0x1C, 0x96, 0x07, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x08, 0x02, 0x3D,
- 0x17, 0x96, 0x02, 0x00, 0x08, 0x1E, 0x1C, 0x96, 0x07, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x08,
- 0x10, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x1B, 0x52, 0x17, 0x96, 0x08, 0x00, 0x07, 0x07, 0x00, 0x00,
- 0x00, 0x02, 0x08, 0x1E, 0x1C, 0x96, 0x07, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x3D,
- 0x17, 0x96, 0x07, 0x00, 0x08, 0x33, 0x07, 0x00, 0x00, 0x00, 0x00, 0x43, 0x1D, 0x96, 0x02, 0x00,
- 0x08, 0x33, 0x1C, 0x96, 0x13, 0x00, 0x08, 0x34, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,
- 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x4F, 0x96, 0x02, 0x00, 0x08, 0x33,
- 0x1C, 0x96, 0x13, 0x00, 0x08, 0x35, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, 0x00, 0x00,
- 0x07, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x3D, 0x4F, 0x96, 0x02, 0x00, 0x08, 0x33, 0x1C, 0x96,
- 0x07, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x08, 0x10, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x1B, 0x52,
- 0x17, 0x96, 0x08, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x02, 0x08, 0x33, 0x1C, 0x96, 0x07, 0x00,
- 0x07, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x3D, 0x17, 0x96, 0x07, 0x00, 0x08, 0x36, 0x07, 0x00,
- 0x00, 0x00, 0x00, 0x43, 0x1D, 0x96, 0x02, 0x00, 0x08, 0x36, 0x1C, 0x96, 0x07, 0x00, 0x07, 0x01,
- 0x00, 0x00, 0x00, 0x08, 0x10, 0x1C, 0x96, 0x02, 0x00, 0x08, 0x1B, 0x52, 0x17, 0x96, 0x0E, 0x00,
- 0x07, 0x01, 0x00, 0x00, 0x00, 0x08, 0x37, 0x07, 0x9A, 0x02, 0x00, 0x00, 0x08, 0x36, 0x1C, 0x96,
- 0x07, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x08, 0x03, 0x3D, 0x17, 0x96, 0x0E, 0x00, 0x07, 0x64,
- 0x00, 0x00, 0x00, 0x08, 0x38, 0x07, 0x9A, 0x02, 0x00, 0x00, 0x08, 0x36, 0x1C, 0x96, 0x07, 0x00,
- 0x07, 0x04, 0x00, 0x00, 0x00, 0x08, 0x03, 0x3D, 0x17, 0x96, 0x02, 0x00, 0x08, 0x39, 0x9B, 0x05,
- 0x00, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x96, 0x02, 0x00, 0x08, 0x0B, 0x1C, 0x96, 0x04, 0x00, 0x08,
- 0x3A, 0x05, 0x00, 0x4F, 0x96, 0x08, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x02, 0x08, 0x0B, 0x1C,
- 0x96, 0x07, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x3D, 0x17, 0x96, 0x13, 0x00, 0x08,
- 0x3B, 0x07, 0xC8, 0x00, 0x00, 0x00, 0x07, 0x34, 0x08, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00,
- 0x08, 0x01, 0x3D, 0x3C, 0x96, 0x02, 0x00, 0x08, 0x0B, 0x1C, 0x96, 0x07, 0x00, 0x07, 0x01, 0x00,
- 0x00, 0x00, 0x08, 0x3B, 0x3D, 0x17, 0x96, 0x02, 0x00, 0x08, 0x0B, 0x1C, 0x96, 0x04, 0x00, 0x08,
-