[rygel] core,tests: Merge GstResponse into HTTPResponse
- From: Zeeshan Ali Khattak <zeeshanak src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rygel] core,tests: Merge GstResponse into HTTPResponse
- Date: Sat, 9 Apr 2011 02:09:53 +0000 (UTC)
commit f3ce150d16d03f865792bf849b2c5c1cfc695484
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date: Sat Apr 9 03:27:27 2011 +0300
core,tests: Merge GstResponse into HTTPResponse
po/POTFILES.in | 1 -
po/POTFILES.skip | 4 +-
src/rygel/Makefile.am | 1 -
src/rygel/rygel-http-gst-response.vala | 230 --------------------
src/rygel/rygel-http-gst-sink.vala | 4 +-
src/rygel/rygel-http-identity-handler.vala | 2 +-
src/rygel/rygel-http-response.vala | 203 +++++++++++++++++-
src/rygel/rygel-http-transcode-handler.vala | 2 +-
tests/Makefile.am | 10 +-
tests/rygel-http-gst-response-test.vala | 164 --------------
tests/rygel-http-gst-response.vala | 1 -
tests/rygel-http-response-test.vala | 132 +++++++++++-
tests/rygel-http-response-test_gst-response.vala | 1 -
..._gst-response.vala => rygel-http-response.vala} | 0
...vala => rygel-state-machine_http-response.vala} | 0
15 files changed, 332 insertions(+), 423 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 34ab9e1..d7fec05 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -100,7 +100,6 @@ src/rygel/rygel-item-creator.vala
src/rygel/rygel-item-destroyer.vala
src/rygel/rygel-l16-transcoder-bin.vala
src/rygel/rygel-l16-transcoder.vala
-src/rygel/rygel-http-gst-response.vala
src/rygel/rygel-log-handler.vala
src/rygel/rygel-logical-expression.vala
src/rygel/rygel-main.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 4730ba2..1cac003 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -59,7 +59,7 @@ src/rygel/rygel-import-resource.c
src/rygel/rygel-item-creator.c
src/rygel/rygel-item-destroyer.c
src/rygel/rygel-l16-transcoder-bin.c
-src/rygel/rygel-http-gst-response.c
+src/rygel/rygel-http-response.c
src/rygel/rygel-log-handler.c
src/rygel/rygel-main.c
src/rygel/rygel-media-container.c
@@ -100,7 +100,7 @@ tests/rygel-gst-utils.c
tests/rygel-http-byte-seek.c
tests/rygel-http-item-uri.c
tests/rygel-http-time-seek.c
-tests/rygel-http-gst-response.c
+tests/rygel-http-response.c
tests/rygel-http-byte-seek_http-get.c
tests/rygel-http-get.c
tests/rygel-http-item-uri_http-get.c
diff --git a/src/rygel/Makefile.am b/src/rygel/Makefile.am
index 32d1b78..73c7c69 100644
--- a/src/rygel/Makefile.am
+++ b/src/rygel/Makefile.am
@@ -52,7 +52,6 @@ VAPI_SOURCE_FILES = \
rygel-http-byte-seek.vala \
rygel-http-time-seek.vala \
rygel-http-response.vala \
- rygel-http-gst-response.vala \
rygel-http-gst-sink.vala \
rygel-resource-info.vala \
rygel-icon-info.vala \
diff --git a/src/rygel/rygel-http-gst-sink.vala b/src/rygel/rygel-http-gst-sink.vala
index f70fc98..330f88f 100644
--- a/src/rygel/rygel-http-gst-sink.vala
+++ b/src/rygel/rygel-http-gst-sink.vala
@@ -32,7 +32,7 @@ internal class Rygel.HTTPGstSink : BaseSink {
public Cancellable cancellable;
- private unowned HTTPGstResponse response;
+ private unowned HTTPResponse response;
private int priority;
private int64 chunks_buffered;
@@ -51,7 +51,7 @@ internal class Rygel.HTTPGstSink : BaseSink {
add_pad_template (template);
}
- public HTTPGstSink (HTTPGstResponse response) {
+ public HTTPGstSink (HTTPResponse response) {
this.chunks_buffered = 0;
this.bytes_sent = 0;
this.max_bytes = int64.MAX;
diff --git a/src/rygel/rygel-http-identity-handler.vala b/src/rygel/rygel-http-identity-handler.vala
index cd28b73..00dc465 100644
--- a/src/rygel/rygel-http-identity-handler.vala
+++ b/src/rygel/rygel-http-identity-handler.vala
@@ -88,6 +88,6 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPGetHandler {
throw new HTTPRequestError.NOT_FOUND (_("Not found"));
}
- return new HTTPGstResponse (request, this, src);
+ return new HTTPResponse (request, this, src);
}
}
diff --git a/src/rygel/rygel-http-response.vala b/src/rygel/rygel-http-response.vala
index 28bf86c..98a4026 100644
--- a/src/rygel/rygel-http-response.vala
+++ b/src/rygel/rygel-http-response.vala
@@ -22,14 +22,17 @@
*/
using Gst;
+using Soup;
-internal abstract class Rygel.HTTPResponse : GLib.Object, Rygel.StateMachine {
+internal class Rygel.HTTPResponse : GLib.Object, Rygel.StateMachine {
public Soup.Server server { get; private set; }
public Soup.Message msg;
public Cancellable cancellable { get; set; }
- protected SourceFunc run_continue;
+ public HTTPSeek seek;
+
+ private SourceFunc run_continue;
private int _priority = -1;
public int priority {
get {
@@ -54,30 +57,49 @@ internal abstract class Rygel.HTTPResponse : GLib.Object, Rygel.StateMachine {
}
}
+ private Pipeline pipeline;
+ private uint bus_watch_id;
+
public HTTPResponse (HTTPGet request,
HTTPGetHandler request_handler,
- bool partial) throws Error {
+ Element src) throws Error {
this.server = request.server;
this.msg = request.msg;
this.cancellable = request_handler.cancellable;
+ this.seek = request.seek;
- if (partial) {
+ if (this.seek != null && this.seek.length < this.seek.total_length) {
this.msg.set_status (Soup.KnownStatusCode.PARTIAL_CONTENT);
} else {
this.msg.set_status (Soup.KnownStatusCode.OK);
}
- this.msg.response_body.set_accumulate (false);
+ if (this.seek != null && this.seek is HTTPByteSeek) {
+ this.msg.response_headers.set_encoding (Encoding.CONTENT_LENGTH);
+ } else {
+ this.msg.response_headers.set_encoding (Encoding.EOF);
+ }
if (this.cancellable != null) {
this.cancellable.cancelled.connect (this.on_cancelled);
}
+
+ this.msg.response_body.set_accumulate (false);
+
+ this.prepare_pipeline ("RygelHTTPGstResponse", src);
}
- public abstract async void run ();
+ public async void run () {
+ // Only bother attempting to seek if the offset is greater than zero.
+ if (this.seek != null && this.seek.start > 0) {
+ this.pipeline.set_state (State.PAUSED);
+ } else {
+ this.pipeline.set_state (State.PLAYING);
+ }
+
+ this.run_continue = run.callback;
- private void on_cancelled (Cancellable cancellable) {
- this.end (true, Soup.KnownStatusCode.CANCELLED);
+ yield;
}
public void push_data (uint8[] data) {
@@ -87,6 +109,19 @@ internal abstract class Rygel.HTTPResponse : GLib.Object, Rygel.StateMachine {
}
public virtual void end (bool aborted, uint status) {
+ var sink = this.pipeline.get_by_name (HTTPGstSink.NAME) as HTTPGstSink;
+ sink.cancellable.cancel ();
+
+ this.pipeline.set_state (State.NULL);
+ Source.remove (this.bus_watch_id);
+
+ var encoding = this.msg.response_headers.get_encoding ();
+
+ if (!aborted && encoding != Encoding.CONTENT_LENGTH) {
+ this.msg.response_body.complete ();
+ this.server.unpause_message (this.msg);
+ }
+
if (this.run_continue != null) {
this.run_continue ();
}
@@ -97,4 +132,156 @@ internal abstract class Rygel.HTTPResponse : GLib.Object, Rygel.StateMachine {
this.completed ();
}
+
+ private void on_cancelled (Cancellable cancellable) {
+ this.end (true, Soup.KnownStatusCode.CANCELLED);
+ }
+
+ private void prepare_pipeline (string name,
+ Element src) throws Error {
+ var sink = new HTTPGstSink (this);
+
+ this.pipeline = new Pipeline (name);
+ assert (this.pipeline != null);
+
+ this.pipeline.add_many (src, sink);
+
+ if (src.numpads == 0) {
+ // Seems source uses dynamic pads, link when pad available
+ src.pad_added.connect (this.src_pad_added);
+ } else {
+ // static pads? easy!
+ if (!src.link (sink)) {
+ throw new GstError.LINK (_("Failed to link %s to %s"),
+ src.name,
+ sink.name);
+ }
+ }
+
+ // Bus handler
+ var bus = this.pipeline.get_bus ();
+ this.bus_watch_id = bus.add_watch (this.bus_handler);
+ }
+
+ private void src_pad_added (Element src,
+ Pad src_pad) {
+ var caps = src_pad.get_caps ();
+
+ var sink = this.pipeline.get_by_name (HTTPGstSink.NAME);
+ Pad sink_pad;
+
+ dynamic Element depay = GstUtils.get_rtp_depayloader (caps);
+ if (depay != null) {
+ this.pipeline.add (depay);
+ if (!depay.link (sink)) {
+ critical (_("Failed to link %s to %s"),
+ depay.name,
+ sink.name);
+ this.end (false, KnownStatusCode.NONE);
+ return;
+ }
+
+ sink_pad = depay.get_compatible_pad (src_pad, caps);
+ } else {
+ sink_pad = sink.get_compatible_pad (src_pad, caps);
+ }
+
+ if (src_pad.link (sink_pad) != PadLinkReturn.OK) {
+ critical (_("Failed to link pad %s to %s"),
+ src_pad.name,
+ sink_pad.name);
+ this.end (false, KnownStatusCode.NONE);
+ return;
+ }
+
+ if (depay != null) {
+ depay.sync_state_with_parent ();
+ }
+ }
+
+ private bool bus_handler (Gst.Bus bus,
+ Gst.Message message) {
+ bool ret = true;
+
+ if (message.type == MessageType.EOS) {
+ ret = false;
+ } else if (message.type == MessageType.STATE_CHANGED) {
+ if (message.src != this.pipeline) {
+ return true;
+ }
+
+ if (this.seek != null && this.seek.start > 0) {
+ State old_state;
+ State new_state;
+
+ message.parse_state_changed (out old_state,
+ out new_state,
+ null);
+
+ if (old_state == State.READY && new_state == State.PAUSED) {
+ if (this.perform_seek ()) {
+ this.pipeline.set_state (State.PLAYING);
+ }
+ }
+ }
+ } else {
+ GLib.Error err;
+ string err_msg;
+
+ if (message.type == MessageType.ERROR) {
+ message.parse_error (out err, out err_msg);
+ critical (_("Error from pipeline %s: %s"),
+ this.pipeline.name,
+ err_msg);
+
+ ret = false;
+ } else if (message.type == MessageType.WARNING) {
+ message.parse_warning (out err, out err_msg);
+ warning (_("Warning from pipeline %s: %s"),
+ this.pipeline.name,
+ err_msg);
+ }
+ }
+
+ if (!ret) {
+ Idle.add_full (this.priority, () => {
+ this.end (false, KnownStatusCode.NONE);
+
+ return false;
+ });
+ }
+
+ return ret;
+ }
+
+ private bool perform_seek () {
+ var stop_type = Gst.SeekType.NONE;
+ Format format;
+
+ if (this.seek is HTTPTimeSeek) {
+ format = Format.TIME;
+
+ if (this.seek.stop > 0) {
+ stop_type = Gst.SeekType.SET;
+ }
+ } else {
+ format = Format.BYTES;
+ }
+
+ if (!this.pipeline.seek (1.0,
+ format,
+ SeekFlags.FLUSH | SeekFlags.ACCURATE,
+ Gst.SeekType.SET,
+ this.seek.start,
+ stop_type,
+ this.seek.stop)) {
+ warning (_("Failed to seek to offset %lld"), this.seek.start);
+
+ this.end (false, KnownStatusCode.REQUESTED_RANGE_NOT_SATISFIABLE);
+
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/src/rygel/rygel-http-transcode-handler.vala b/src/rygel/rygel-http-transcode-handler.vala
index 1478879..b1122fc 100644
--- a/src/rygel/rygel-http-transcode-handler.vala
+++ b/src/rygel/rygel-http-transcode-handler.vala
@@ -59,7 +59,7 @@ internal class Rygel.HTTPTranscodeHandler : HTTPGetHandler {
try {
src = this.transcoder.create_source (item, src);
- return new HTTPGstResponse (request, this, src);
+ return new HTTPResponse (request, this, src);
} catch (GLib.Error err) {
throw new HTTPRequestError.NOT_FOUND (err.message);
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6fa71e7..e01705e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -26,7 +26,7 @@ AM_VALAFLAGS = --disable-warnings --thread \
--pkg gio-2.0 --pkg gee-1.0 -g
check_PROGRAMS = rygel-http-item-uri-test \
- rygel-http-gst-response-test \
+ rygel-http-response-test \
rygel-http-byte-seek-test \
rygel-http-time-seek-test \
rygel-http-get-test \
@@ -38,11 +38,9 @@ TESTS = $(check_PROGRAMS)
rygel_http_item_uri_test_SOURCES = rygel-http-item-uri-test.vala \
rygel-http-item-uri.vala
-rygel_http_gst_response_test_SOURCES = rygel-http-gst-response-test.vala \
- rygel-http-gst-response.vala \
- rygel-http-response_gst-response.vala \
- rygel-http-response-test_gst-response.vala \
- rygel-state-machine_gst-response.vala \
+rygel_http_response_test_SOURCES = rygel-http-response-test.vala \
+ rygel-http-response.vala \
+ rygel-state-machine_http-response.vala \
rygel-http-gst-sink.vala \
rygel-gst-utils.vala
diff --git a/tests/rygel-http-response-test.vala b/tests/rygel-http-response-test.vala
index c3e6d8b..0a8e50a 100644
--- a/tests/rygel-http-response-test.vala
+++ b/tests/rygel-http-response-test.vala
@@ -21,16 +21,19 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// This module contains the common code between the test cases for
-// HTTPResponse subclasses.
using Soup;
+using Gst;
public errordomain Rygel.TestError {
SKIP = 77,
TIMEOUT
}
-public abstract class Rygel.HTTPResponseTest : GLib.Object {
+public errordomain Rygel.HTTPRequestError {
+ NOT_FOUND = Soup.KnownStatusCode.NOT_FOUND
+}
+
+public class Rygel.HTTPResponseTest : GLib.Object {
public const long MAX_BYTES = 102400;
protected HTTPServer server;
@@ -39,11 +42,33 @@ public abstract class Rygel.HTTPResponseTest : GLib.Object {
private bool server_done;
private bool client_done;
+ private MediaItem item;
+
private MainLoop main_loop;
protected Cancellable cancellable;
private Error error;
+ public static int main (string[] args) {
+ Gst.init (ref args);
+
+ try {
+ var test = new HTTPResponseTest.complete ();
+ test.run ();
+
+ test = new HTTPResponseTest.abort ();
+ test.run ();
+ } catch (TestError.SKIP error) {
+ return error.code;
+ } catch (Error error) {
+ critical ("%s", error.message);
+
+ return -1;
+ }
+
+ return 0;
+ }
+
public HTTPResponseTest (Cancellable? cancellable = null) throws Error {
this.cancellable = cancellable;
@@ -57,10 +82,14 @@ public abstract class Rygel.HTTPResponseTest : GLib.Object {
public HTTPResponseTest.complete () throws Error {
this ();
+
+ this.item = new MediaItem.fixed_size ();
}
public HTTPResponseTest.abort () throws Error {
this (new Cancellable ());
+
+ this.item = new MediaItem ();
}
public virtual void run () throws Error {
@@ -82,8 +111,24 @@ public abstract class Rygel.HTTPResponseTest : GLib.Object {
}
}
- internal abstract HTTPResponse create_response (Soup.Message msg)
- throws Error;
+ private HTTPResponse create_response (Soup.Message msg) throws Error {
+ var seek = null as HTTPSeek;
+
+ if (!this.item.is_live_stream ()) {
+ seek = new HTTPByteSeek (0, MAX_BYTES - 1, this.item.size);
+ msg.response_headers.set_content_length (seek.length);
+ }
+
+ var request = new HTTPGet (this.server.context.server,
+ msg,
+ this.item,
+ seek,
+ this.cancellable);
+ var handler = new HTTPGetHandler (this.cancellable);
+ var src = this.item.create_stream_source ();
+
+ return new HTTPResponse (request, handler, src);
+ }
private void on_client_completed (StateMachine client) {
if (this.server_done) {
@@ -247,3 +292,80 @@ public class Rygel.HTTPSeek : GLib.Object {
this.length = stop - start + 1;
}
}
+
+public class Rygel.HTTPByteSeek : Rygel.HTTPSeek {
+ public HTTPByteSeek (int64 start, int64 stop, int64 total_length) {
+ base (start, stop, total_length);
+ }
+}
+
+public class Rygel.HTTPTimeSeek : Rygel.HTTPSeek {
+ public HTTPTimeSeek (int64 start, int64 stop, int64 total_length) {
+ base (start, stop, total_length);
+ }
+}
+
+public class Rygel.HTTPGet : GLib.Object {
+ public Soup.Server server;
+ public Soup.Message msg;
+
+ public Cancellable cancellable;
+
+ public MediaItem item;
+
+ internal HTTPSeek seek;
+
+ public HTTPGet (Soup.Server server,
+ Soup.Message msg,
+ MediaItem item,
+ HTTPSeek? seek,
+ Cancellable? cancellable) {
+ this.server = server;
+ this.msg = msg;
+ this.item = item;
+ this.seek = seek;
+ this.cancellable = cancellable;
+ }
+}
+
+public class Rygel.HTTPGetHandler : GLib.Object {
+ public Cancellable cancellable;
+
+ public HTTPGetHandler (Cancellable? cancellable) {
+ this.cancellable = cancellable;
+ }
+}
+
+public class Rygel.MediaItem {
+ private static const long BLOCK_SIZE = HTTPResponseTest.MAX_BYTES / 16 + 1;
+ private static const long MAX_BUFFERS = 25;
+
+ public int64 size {
+ get {
+ return MAX_BUFFERS * BLOCK_SIZE;
+ }
+ }
+
+ private dynamic Element src;
+
+ public MediaItem () {
+ this.src = GstUtils.create_element ("fakesrc", null);
+ this.src.sizetype = 2; // fixed
+ }
+
+ public MediaItem.fixed_size () {
+ this ();
+
+ this.src.blocksize = BLOCK_SIZE;
+ this.src.num_buffers = MAX_BUFFERS;
+ this.src.sizemax = MAX_BUFFERS * BLOCK_SIZE;
+ }
+
+ public Element? create_stream_source () {
+ return this.src;
+ }
+
+ public bool is_live_stream () {
+ return ((int) this.src.num_buffers) < 0;
+ }
+}
diff --git a/tests/rygel-http-response_gst-response.vala b/tests/rygel-http-response.vala
similarity index 100%
rename from tests/rygel-http-response_gst-response.vala
rename to tests/rygel-http-response.vala
diff --git a/tests/rygel-state-machine_gst-response.vala b/tests/rygel-state-machine_http-response.vala
similarity index 100%
rename from tests/rygel-state-machine_gst-response.vala
rename to tests/rygel-state-machine_http-response.vala
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]