2 * Copyright (C) 2010 Nokia Corporation.
4 * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
5 * <zeeshan.ali@nokia.com>
7 * This file is part of Rygel.
9 * Rygel is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * Rygel is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 public errordomain Rygel.TestError {
32 public errordomain Rygel.ClientHacksError {
36 public class Rygel.ClientHacks {
37 public static ClientHacks create_for_headers (MessageHeaders headers) throws Error {
38 throw new ClientHacksError.NA ("");
41 public bool is_album_art_request (Message message) {
45 public void apply (MediaItem item) {
49 public class Rygel.HTTPGetTest : GLib.Object {
50 protected HTTPServer server;
51 protected HTTPClient client;
53 private bool server_done;
54 private bool client_done;
56 private MainLoop main_loop;
60 public static int main (string[] args) {
62 var test = new HTTPGetTest ();
65 } catch (TestError.SKIP error) {
67 } catch (Error error) {
68 critical ("%s", error.message);
76 public HTTPGetTest () throws Error {
77 this.server = new HTTPServer ();
78 this.client = new HTTPClient (this.server.context,
80 this.main_loop = new MainLoop (null, false);
83 public virtual void run () throws Error {
84 Timeout.add_seconds (3, this.on_timeout);
85 this.server.message_received.connect (this.on_message_received);
86 this.client.completed.connect (this.on_client_completed);
88 this.client.run.begin ();
90 this.main_loop.run ();
92 if (this.error != null) {
97 private HTTPRequest create_request (Soup.Message msg) throws Error {
98 return new HTTPGet (this.server,
99 this.server.context.server,
103 private void on_client_completed (StateMachine client) {
104 if (this.server_done) {
105 this.main_loop.quit ();
108 this.client_done = true;
111 private void on_message_received (HTTPServer server,
113 this.handle_client_message.begin (msg);
116 private async void handle_client_message (Soup.Message msg) {
118 var request = this.create_request (msg);
120 yield request.run ();
122 assert ((request as HTTPGet).item != null);
124 if (this.client_done) {
125 this.main_loop.quit ();
128 this.server_done = true;
129 } catch (Error error) {
131 this.main_loop.quit ();
137 private bool on_timeout () {
138 this.error = new TestError.TIMEOUT ("Timeout");
139 this.main_loop.quit ();
145 public class Rygel.HTTPServer : GLib.Object {
146 private const string SERVER_PATH = "/RygelHTTPServer/Rygel/Test";
147 public string path_root {
153 public MediaContainer root_container;
154 public GUPnP.Context context;
158 var item_uri = new HTTPItemURI (this.root_container.ITEM_ID,
161 return item_uri.to_string ();
165 public signal void message_received (Soup.Message message);
167 public HTTPServer () throws TestError {
169 this.context = new GUPnP.Context (null, "lo", 0);
170 } catch (Error error) {
171 throw new TestError.SKIP ("Network context not available");
174 assert (this.context != null);
175 assert (this.context.host_ip != null);
176 assert (this.context.port > 0);
178 this.context.server.add_handler (SERVER_PATH, this.server_cb);
180 this.root_container = new MediaContainer ();
183 private void server_cb (Server server,
187 ClientContext client) {
188 this.context.server.pause_message (msg);
189 this.message_received (msg);
192 public Transcoder get_transcoder (string target) throws Error {
193 return new Transcoder ();
197 public class Rygel.HTTPClient : GLib.Object, StateMachine {
198 public GUPnP.Context context;
199 public Soup.Message msg;
201 public Cancellable cancellable { get; set; }
203 public HTTPClient (GUPnP.Context context,
205 this.context = context;
207 this.msg = new Soup.Message ("GET", uri);
208 assert (this.msg != null);
211 public async void run () {
212 SourceFunc run_continue = run.callback;
214 this.context.session.queue_message (this.msg, (session, msg) => {
224 public class Rygel.MediaContainer : Rygel.MediaObject {
225 public const string ITEM_ID = "TestItem";
227 public async MediaObject? find_object (string item_id,
228 Cancellable? cancellable)
230 SourceFunc find_object_continue = find_object.callback;
232 find_object_continue ();
239 if (item_id == ITEM_ID) {
240 return new VideoItem ();
247 internal abstract class Rygel.HTTPGetHandler {
248 public HTTPResponse render_body (HTTPGet get_request) {
249 return new HTTPResponse (get_request);
252 public void add_response_headers (HTTPGet get_request) {}
255 internal class Rygel.HTTPTranscodeHandler : Rygel.HTTPGetHandler {
256 public HTTPTranscodeHandler (Transcoder transcoder,
257 Cancellable cancellable) {}
260 internal class Rygel.HTTPIdentityHandler : Rygel.HTTPGetHandler {
261 public HTTPIdentityHandler (Cancellable cancellable) {}
264 public abstract class Rygel.MediaItem : Rygel.MediaObject {
265 public long size = 1024;
266 public ArrayList<Subtitle> subtitles = new ArrayList<Subtitle> ();
267 public ArrayList<Thumbnail> thumbnails = new ArrayList<Thumbnail> ();
269 public bool place_holder = false;
271 public bool is_live_stream () {
275 public bool streamable () {
280 private class Rygel.AudioItem : MediaItem {
281 public int64 duration = 2048;
284 private interface Rygel.VisualItem : MediaItem {
285 public abstract int width { get; set; }
286 public abstract int height { get; set; }
287 public abstract int pixel_width { get; set; }
288 public abstract int pixel_height { get; set; }
289 public abstract int color_depth { get; set; }
291 public abstract ArrayList<Thumbnail> thumbnails { get; protected set; }
294 private class Rygel.VideoItem : AudioItem, VisualItem {
295 public int width { get; set; default = -1; }
296 public int height { get; set; default = -1; }
297 public int pixel_width { get; set; default = -1; }
298 public int pixel_height { get; set; default = -1; }
299 public int color_depth { get; set; default = -1; }
301 public ArrayList<Thumbnail> thumbnails { get; protected set; }
302 public ArrayList<Subtitle> subtitles;
305 private class Rygel.MusicItem : AudioItem {
306 public Thumbnail album_art;
309 public class Rygel.Thumbnail {
310 public long size = 1024;
313 public class Rygel.Subtitle {
314 public long size = 1024;
317 internal class Rygel.HTTPResponse : Rygel.StateMachine, GLib.Object {
318 public Cancellable cancellable { get; set; }
320 private Soup.Message msg;
321 private Soup.Server server;
323 public HTTPResponse (HTTPGet get_request) {
324 this.msg = get_request.msg;
325 this.msg.response_headers.set_encoding (Soup.Encoding.CONTENT_LENGTH);
326 this.server = get_request.server;
329 public async void run () {
330 SourceFunc run_continue = run.callback;
340 this.msg.set_status (Soup.KnownStatusCode.OK);
341 this.server.unpause_message (msg);
347 public class Rygel.MediaObject {
351 public class Rygel.Transcoder {}