[rygel] server: Add a M3U resource to containers
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rygel] server: Add a M3U resource to containers
- Date: Mon, 17 Jun 2013 12:43:55 +0000 (UTC)
commit 63bc34de234634345e2e301cdda4c4d35ef916fd
Author: Jens Georg <jensg openismus com>
Date: Sun Jun 16 11:22:31 2013 +0200
server: Add a M3U resource to containers
src/librygel-server/filelist.am | 1 +
src/librygel-server/rygel-http-get.vala | 6 +-
.../rygel-http-playlist-handler.vala | 40 +++++++++--
src/librygel-server/rygel-m3u-playlist.vala | 79 ++++++++++++++++++++
src/librygel-server/rygel-media-container.vala | 67 +++++++++++------
src/librygel-server/rygel-serializer.vala | 56 +++++++++++---
6 files changed, 206 insertions(+), 43 deletions(-)
---
diff --git a/src/librygel-server/filelist.am b/src/librygel-server/filelist.am
index dec2e1e..fcc0bbc 100644
--- a/src/librygel-server/filelist.am
+++ b/src/librygel-server/filelist.am
@@ -62,6 +62,7 @@ LIBRYGEL_SERVER_NONVAPI_SOURCE_FILES = \
rygel-last-change-obj-mod.vala \
rygel-last-change-st-done.vala \
rygel-last-change.vala \
+ rygel-m3u-playlist.vala \
rygel-media-query-action.vala \
rygel-media-receiver-registrar.vala \
rygel-panasonic-hacks.vala \
diff --git a/src/librygel-server/rygel-http-get.vala b/src/librygel-server/rygel-http-get.vala
index e977cea..d8882fc 100644
--- a/src/librygel-server/rygel-http-get.vala
+++ b/src/librygel-server/rygel-http-get.vala
@@ -66,8 +66,10 @@ internal class Rygel.HTTPGet : HTTPRequest {
this.cancellable);
}
- if (uri.playlist_format != null) {
- this.handler = new HTTPPlaylistHandler (this.cancellable);
+ if (uri.playlist_format != null &&
+ HTTPPlaylistHandler.is_supported (uri.playlist_format)) {
+ this.handler = new HTTPPlaylistHandler (uri.playlist_format,
+ this.cancellable);
}
if (this.handler == null) {
diff --git a/src/librygel-server/rygel-http-playlist-handler.vala
b/src/librygel-server/rygel-http-playlist-handler.vala
index 7adf0b7..e2a4e39 100644
--- a/src/librygel-server/rygel-http-playlist-handler.vala
+++ b/src/librygel-server/rygel-http-playlist-handler.vala
@@ -29,10 +29,13 @@ internal class Rygel.PlaylistDatasource : Rygel.DataSource, Object {
private uint8[] data;
private HTTPServer server;
private ClientHacks hacks;
+ private SerializerType playlist_type;
- public PlaylistDatasource (MediaContainer container,
+ public PlaylistDatasource (SerializerType playlist_type,
+ MediaContainer container,
HTTPServer server,
ClientHacks? hacks) {
+ this.playlist_type = playlist_type;
this.container = container;
this.server = server;
this.hacks = hacks;
@@ -82,7 +85,7 @@ internal class Rygel.PlaylistDatasource : Rygel.DataSource, Object {
null);
if (children != null) {
- var serializer = new Serializer (SerializerType.DIDL_S);
+ var serializer = new Serializer (this.playlist_type);
children.serialize (serializer, this.server, this.hacks);
var xml = serializer.get_string ();
@@ -105,13 +108,38 @@ internal class Rygel.PlaylistDatasource : Rygel.DataSource, Object {
* playlists (DIDL_S format as defined by DLNA) on-the-fly.
*/
internal class Rygel.HTTPPlaylistHandler : Rygel.HTTPGetHandler {
- public HTTPPlaylistHandler (Cancellable? cancellable) {
+ private SerializerType playlist_type;
+
+ public static bool is_supported (string playlist_format) {
+ return playlist_format == "DIDL_S" || playlist_format == "M3U";
+ }
+
+ public HTTPPlaylistHandler (string playlist_format,
+ Cancellable? cancellable) {
+ if (playlist_format == "DIDL_S") {
+ this.playlist_type = SerializerType.DIDL_S;
+ } else if (playlist_format == "M3U") {
+ this.playlist_type = SerializerType.M3UEXT;
+ }
+
this.cancellable = cancellable;
}
public override void add_response_headers (HTTPGet request)
throws HTTPRequestError {
- request.msg.response_headers.append ("Content-Type", "text/xml");
+ // TODO: Why do we use response_headers.append instead of set_content_type
+ switch (this.playlist_type) {
+ case SerializerType.DIDL_S:
+ request.msg.response_headers.append ("Content-Type",
+ "text/xml");
+ break;
+ case SerializerType.M3UEXT:
+ request.msg.response_headers.append ("ContentType",
+ "audio/x-mpegurl");
+ break;
+ default:
+ assert_not_reached ();
+ }
base.add_response_headers (request);
}
@@ -120,7 +148,8 @@ internal class Rygel.HTTPPlaylistHandler : Rygel.HTTPGetHandler {
throws HTTPRequestError {
try {
var source = new PlaylistDatasource
- (request.object as MediaContainer,
+ (this.playlist_type,
+ request.object as MediaContainer,
request.http_server,
request.hack);
@@ -134,7 +163,6 @@ internal class Rygel.HTTPPlaylistHandler : Rygel.HTTPGetHandler {
(DIDLLiteObject didl_object,
HTTPGet request) {
var protocol = request.http_server.get_protocol ();
- debug ("=> Protocol of this http server is: %s", protocol);
try {
return request.object.add_resource (didl_object, null, protocol);
diff --git a/src/librygel-server/rygel-m3u-playlist.vala b/src/librygel-server/rygel-m3u-playlist.vala
new file mode 100644
index 0000000..ae333dd
--- /dev/null
+++ b/src/librygel-server/rygel-m3u-playlist.vala
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 Jens Georg.
+ *
+ * Authors: Jens Georg <mail jensge org>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Gee;
+using GUPnP;
+
+/**
+ * Serializer class that serializes to an EXTM3U playlist for use with normal
+ * media players or UPnP Renderers that don't support DIDL_S.
+ *
+ * For the description of the EXTM3U format, see
+ * http://en.wikipedia.org/wiki/M3U#Extended_M3U_directives
+ */
+internal class Rygel.M3UPlayList : Object {
+ private LinkedList<DIDLLiteItem> items;
+
+ // We need this writer for the namespaces, the document etc.
+ private DIDLLiteWriter writer;
+
+ public M3UPlayList () {
+ Object ();
+ }
+
+ public override void constructed () {
+ this.items = new LinkedList<DIDLLiteItem> ();
+ this.writer = new DIDLLiteWriter (null);
+ }
+
+
+ public DIDLLiteItem? add_item () {
+ this.items.add (this.writer.add_item ());
+
+ return this.items.last ();
+ }
+
+ public string get_string () {
+ var builder = new StringBuilder ("#EXTM3U\r\n");
+
+ foreach (var item in this.items) {
+ var resources = item.get_resources ();
+ if (resources != null) {
+ var authors = item.get_artists ();
+ builder.append_printf ("#EXTINF:%ld,",
+ resources.data.duration);
+ if (authors != null) {
+ builder.append_printf ("%s - ",
+ authors.data.get_name () ??
+ _("Unknown"));
+ }
+
+ builder.append (item.title ?? _("Unknown"));
+ builder.append ("\r\n");
+ builder.append (resources.data.uri);
+ builder.append ("\r\n");
+ }
+ }
+
+ return builder.str;
+ }
+}
diff --git a/src/librygel-server/rygel-media-container.vala b/src/librygel-server/rygel-media-container.vala
index 97ecfb1..4ae62e1 100644
--- a/src/librygel-server/rygel-media-container.vala
+++ b/src/librygel-server/rygel-media-container.vala
@@ -310,6 +310,15 @@ public abstract class Rygel.MediaContainer : MediaObject {
didl_container.restricted = true;
}
+ this.add_resources (http_server, didl_container);
+
+ return didl_container;
+ }
+
+ internal void add_resources (Rygel.HTTPServer http_server,
+ DIDLLiteContainer didl_container)
+ throws Error {
+ // Add resource with container contents serialized to DIDL_S playlist
var uri = new HTTPItemURI (this,
http_server,
-1,
@@ -318,11 +327,24 @@ public abstract class Rygel.MediaContainer : MediaObject {
"DIDL_S");
uri.extension = "xml";
- this.add_resource (didl_container,
- uri.to_string (),
- http_server.get_protocol ());
+ var res = this.add_resource (didl_container,
+ uri.to_string (),
+ http_server.get_protocol ());
+ if (res != null) {
+ res.protocol_info.mime_type = "text/xml";
+ res.protocol_info.dlna_profile = "DIDL_S";
+ }
- return didl_container;
+ // Add resource with container contents serialized to M3U playlist
+ uri = new HTTPItemURI (this, http_server, -1, -1, null, "M3U");
+ uri.extension = "m3u";
+
+ res = this.add_resource (didl_container,
+ uri.to_string (),
+ http_server.get_protocol ());
+ if (res != null) {
+ res.protocol_info.mime_type = "audio/x-mpegurl";
+ }
}
internal override DIDLLiteResource add_resource
@@ -331,29 +353,28 @@ public abstract class Rygel.MediaContainer : MediaObject {
string protocol,
string? import_uri = null)
throws Error {
- if (this.child_count > 0) {
- var res = base.add_resource (didl_object,
- uri,
- protocol,
- import_uri);
-
- if (uri != null) {
- res.uri = uri;
- }
+ if (this.child_count <= 0) {
+ return null as DIDLLiteResource;
+ }
- var protocol_info = new ProtocolInfo ();
- protocol_info.mime_type = "text/xml";
- protocol_info.dlna_profile = "DIDL_S";
- protocol_info.protocol = protocol;
- protocol_info.dlna_flags = DLNAFlags.DLNA_V15 |
- DLNAFlags.CONNECTION_STALL |
- DLNAFlags.BACKGROUND_TRANSFER_MODE;
- res.protocol_info = protocol_info;
+ var res = base.add_resource (didl_object,
+ uri,
+ protocol,
+ import_uri);
- return res;
+ if (uri != null) {
+ res.uri = uri;
}
- return null as DIDLLiteResource;
+ var protocol_info = new ProtocolInfo ();
+ protocol_info.mime_type = "";
+ protocol_info.protocol = protocol;
+ protocol_info.dlna_flags = DLNAFlags.DLNA_V15 |
+ DLNAFlags.CONNECTION_STALL |
+ DLNAFlags.BACKGROUND_TRANSFER_MODE;
+ res.protocol_info = protocol_info;
+
+ return res;
}
/**
diff --git a/src/librygel-server/rygel-serializer.vala b/src/librygel-server/rygel-serializer.vala
index e7a411b..0e56022 100644
--- a/src/librygel-server/rygel-serializer.vala
+++ b/src/librygel-server/rygel-serializer.vala
@@ -23,40 +23,67 @@
using GUPnP;
internal enum SerializerType {
+ /// Normal serialization of container/item using DIDL-Lite
GENERIC_DIDL,
- DIDL_S
+
+ /// Special version of a DIDL-Lite document for playlists, defined by DLNA
+ DIDL_S,
+
+ /// M3UEXT format as used by various media players
+ M3UEXT
}
+/**
+ * Proxy class hiding the different serializers (DIDL, DIDL_S, M3U) behind a
+ * single implementation.
+ */
internal class Rygel.Serializer : Object {
private DIDLLiteWriter writer;
private MediaCollection collection;
+ private M3UPlayList playlist;
+
+ // private properties
+ public SerializerType serializer_type { construct; private get; }
public Serializer (SerializerType type) {
- switch (type) {
+ Object (serializer_type: type);
+ }
+
+ public override void constructed () {
+ switch (this.serializer_type) {
case SerializerType.GENERIC_DIDL:
this.writer = new DIDLLiteWriter (null);
break;
case SerializerType.DIDL_S:
this.collection = new MediaCollection ();
break;
+ case SerializerType.M3UEXT:
+ this.playlist = new M3UPlayList ();
+ break;
default:
assert_not_reached ();
}
+
+ base.constructed ();
}
public DIDLLiteItem? add_item () {
- if (writer != null) {
- return this.writer.add_item ();
- } else {
- return this.collection.add_item ();
+ switch (this.serializer_type) {
+ case SerializerType.GENERIC_DIDL:
+ return this.writer.add_item ();
+ case SerializerType.DIDL_S:
+ return this.collection.add_item ();
+ case SerializerType.M3UEXT:
+ return this.playlist.add_item ();
+ default:
+ return null;
}
}
public DIDLLiteContainer? add_container () {
- if (writer != null) {
+ if (this.writer != null) {
return this.writer.add_container ();
} else {
- // MediaCollection does not support this.
return null;
}
}
@@ -68,10 +95,15 @@ internal class Rygel.Serializer : Object {
}
public string get_string () {
- if (writer != null) {
- return this.writer.get_string ();
- } else {
- return this.collection.get_string ();
+ switch (this.serializer_type) {
+ case SerializerType.GENERIC_DIDL:
+ return this.writer.get_string ();
+ case SerializerType.DIDL_S:
+ return this.collection.get_string ();
+ case SerializerType.M3UEXT:
+ return this.playlist.get_string ();
+ default:
+ return "";
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]