[rygel/wip/didl-s: 16/25] WIP
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rygel/wip/didl-s: 16/25] WIP
- Date: Tue, 20 Nov 2012 16:11:43 +0000 (UTC)
commit 9d97fee1b94545acad8b07a49f76885907a576d7
Author: Jens Georg <jensg openismus com>
Date: Mon Nov 19 17:29:33 2012 +0100
WIP
data/xml/AVTransport2.xml.in | 1 +
src/librygel-renderer/filelist.am | 1 +
src/librygel-renderer/rygel-av-transport.vala | 167 +++++++++++++++++---
src/librygel-renderer/rygel-playlist-handler.vala | 55 +++++++
.../rygel-sink-connection-manager.vala | 12 ++
5 files changed, 214 insertions(+), 22 deletions(-)
---
diff --git a/data/xml/AVTransport2.xml.in b/data/xml/AVTransport2.xml.in
index 3344a15..fdda8ae 100644
--- a/data/xml/AVTransport2.xml.in
+++ b/data/xml/AVTransport2.xml.in
@@ -281,6 +281,7 @@
<allowedValueList>
<allowedValue>ABS_TIME</allowedValue>
<allowedValue>REL_TIME</allowedValue>
+ <allowedValue>TRACK_NR</allowedValue>
</allowedValueList>
</stateVariable>
diff --git a/src/librygel-renderer/filelist.am b/src/librygel-renderer/filelist.am
index 5048e79..352b8ce 100644
--- a/src/librygel-renderer/filelist.am
+++ b/src/librygel-renderer/filelist.am
@@ -5,6 +5,7 @@ LIBRYGEL_RENDERER_VAPI_SOURCE_FILES = \
LIBRYGEL_RENDERER_NONVAPI_SOURCE_FILES = \
rygel-av-transport.vala \
+ rygel-playlist-handler.vala \
rygel-rendering-control.vala \
rygel-sink-connection-manager.vala \
rygel-time-utils.vala \
diff --git a/src/librygel-renderer/rygel-av-transport.vala b/src/librygel-renderer/rygel-av-transport.vala
index 7d5ff18..c7a204d 100644
--- a/src/librygel-renderer/rygel-av-transport.vala
+++ b/src/librygel-renderer/rygel-av-transport.vala
@@ -35,6 +35,7 @@ internal class Rygel.AVTransport : Service {
"urn:schemas-upnp-org:metadata-1-0/AVT/";
private Session session;
+ private PlaylistHandler playlist_handler;
// The setters below update the LastChange message
private uint _n_tracks = 0;
@@ -67,6 +68,9 @@ internal class Rygel.AVTransport : Service {
public string metadata {
owned get {
if (this._metadata != null) {
+ if (this._metadata.has_prefix ("<")) {
+ return this._metadata;
+ }
return Markup.escape_text (this._metadata);
} else {
return "";
@@ -75,11 +79,28 @@ internal class Rygel.AVTransport : Service {
set {
this._metadata = value;
+ }
+ }
+
+ public string track_metadata {
+ owned get {
+ if (this.player.metadata != null) {
+ if (this.player.metadata.has_prefix ("<")) {
+ return this.player.metadata;
+ }
+
+ return Markup.escape_text (this.player.metadata);
+ } else {
+ return "";
+ }
+ }
+
+ set {
this.player.metadata = value;
}
}
- public string uri {
+ public string track_uri {
owned get {
if (this.player.uri != null) {
return Markup.escape_text (this.player.uri);
@@ -93,6 +114,24 @@ internal class Rygel.AVTransport : Service {
}
}
+ private string _uri;
+ public string uri {
+ owned get {
+ if (this._uri == null) {
+ return "";
+ }
+
+ return this._uri;
+ }
+
+ set {
+ this._uri = value;
+ this.changelog.log ("AVTransportURI", this._uri);
+ }
+ }
+
+
+
private string _status = "OK";
public string status {
get {
@@ -193,9 +232,9 @@ internal class Rygel.AVTransport : Service {
log.log ("CurrentTrack", this.track.to_string ());
log.log ("CurrentTrackDuration", this.player.duration_as_str);
log.log ("CurrentMediaDuration", this.player.duration_as_str);
- log.log ("CurrentTrackMetaData", this.metadata);
+ log.log ("CurrentTrackMetaData", this.track_metadata);
log.log ("AVTransportURIMetaData", this.metadata);
- log.log ("CurrentTrackURI", this.uri);
+ log.log ("CurrentTrackURI", this.track_uri);
log.log ("AVTransportURI", this.uri);
log.log ("NextAVTransportURI", "NOT_IMPLEMENTED");
log.log ("NextAVTransportURIMetaData", "NOT_IMPLEMENTED");
@@ -256,25 +295,41 @@ internal class Rygel.AVTransport : Service {
return;
} else {
var mime = msg.response_headers.get_one ("Content-Type");
+ var features = msg.response_headers.get_one
+ ("contentFeatures.dlna.org");
+
if (mime != null &&
- !(mime in this.player.get_mime_types ())) {
+ !(mime in this.player.get_mime_types () || mime ==
+ "text/xml")) {
action.return_error (714, "Illegal MIME-type");
return;
}
- this.player.mime_type = mime;
- var features = msg.response_headers.get_one
- ("contentFeatures.dlna.org");
-
- if (features != null) {
- this.player.content_features = features;
- } else {
- this.player.content_features = "*";
- }
this.metadata = _metadata;
this.uri = _uri;
- this.n_tracks = 1;
+
+ if (mime == "text/xml" &&
+ features.has_prefix ("DLNA.ORG_PN=DIDL_S")) {
+ // this is a playlist, we'll handle that internally
+ // Return action, then handle playlist
+ // first thing handle playlist does is defer to
+ // mainloop so the action will be returned first.
+ this.handle_playlist.begin ();
+ } else {
+ // some other track
+ this.player.mime_type = mime;
+ if (features != null) {
+ this.player.content_features = features;
+ } else {
+ this.player.content_features = "*";
+ }
+
+ // Track == Media
+ this.track_metadata = _metadata;
+ this.track_uri = _uri;
+ this.n_tracks = 1;
+ }
action.return ();
}
@@ -299,12 +354,21 @@ internal class Rygel.AVTransport : Service {
return;
}
+ string media_duration;
+ if (this.playlist_handler != null) {
+ // We don't know the size of the playlist. Might need change if we
+ // support playlists whose size we know in advance
+ media_duration = "0:00:00";
+ } else {
+ media_duration = this.player.duration_as_str;
+ }
+
action.set ("NrTracks",
typeof (uint),
this.n_tracks,
"MediaDuration",
typeof (string),
- this.player.duration_as_str,
+ media_duration,
"CurrentURI",
typeof (string),
this.uri,
@@ -336,6 +400,15 @@ internal class Rygel.AVTransport : Service {
return;
}
+ string media_duration;
+ if (this.playlist_handler != null) {
+ // We don't know the size of the playlist. Might need change if we
+ // support playlists whose size we know in advance
+ media_duration = "0:00:00";
+ } else {
+ media_duration = this.player.duration_as_str;
+ }
+
action.set ("CurrentType",
typeof (string),
"NO_MEDIA",
@@ -344,7 +417,7 @@ internal class Rygel.AVTransport : Service {
this.n_tracks,
"MediaDuration",
typeof (string),
- this.player.duration_as_str,
+ media_duration,
"CurrentURI",
typeof (string),
this.uri,
@@ -404,10 +477,10 @@ internal class Rygel.AVTransport : Service {
this.player.duration_as_str,
"TrackMetaData",
typeof (string),
- this.metadata,
+ this.track_metadata,
"TrackURI",
typeof (string),
- this.uri,
+ this.track_uri,
"RelTime",
typeof (string),
this.player.position_as_str,
@@ -531,6 +604,27 @@ internal class Rygel.AVTransport : Service {
action.return ();
return;
+ case "TRACK_NR":
+ debug ("Setting track to %s.", target);
+ if (this.playlist_handler == null) {
+ action.return_error (710, _("Seek mode not supported"));
+
+ return;
+ }
+
+ var track = int.parse (target);
+
+ if (track < 1 || track > this.n_tracks) {
+ action.return_error (711, _("Illegal seek target"));
+
+ return;
+ }
+ this.playlist_handler.current_track = track;
+ this.playlist_handler.set_track ();
+
+ action.return();
+
+ break;
default:
action.return_error (710, _("Seek mode not supported"));
@@ -539,11 +633,21 @@ internal class Rygel.AVTransport : Service {
}
private void next_cb (Service service, ServiceAction action) {
- action.return_error (701, _("Transition not available"));
+ if (this.playlist_handler != null) {
+ this.playlist_handler.next ();
+ action.return ();
+ } else {
+ action.return_error (701, _("Transition not available"));
+ }
}
private void previous_cb (Service service, ServiceAction action) {
- action.return_error (701, _("Transition not available"));
+ if (this.playlist_handler != null) {
+ this.playlist_handler.previous ();
+ action.return ();
+ } else {
+ action.return_error (701, _("Transition not available"));
+ }
}
private void notify_state_cb (Object player, ParamSpec p) {
@@ -558,12 +662,31 @@ internal class Rygel.AVTransport : Service {
}
private void notify_uri_cb (Object player, ParamSpec p) {
- this.changelog.log ("CurrentTrackURI", this.uri);
- this.changelog.log ("AVTransportURI", this.uri);
+ this.changelog.log ("CurrentTrackURI", this.track_uri);
}
private void notify_meta_data_cb (Object player, ParamSpec p) {
this._metadata = this.player.metadata;
this.changelog.log ("CurrentTrackMetadata", this.metadata);
}
+
+ private async void handle_playlist () {
+ Idle.add ( () => { handle_playlist.callback (); return false; });
+ yield;
+
+ var message = new Message ("GET", this.uri);
+ this.session.queue_message (message, () => {
+ handle_playlist.callback ();
+ });
+ yield;
+
+ if (message.status_code != 200) {
+ return;
+ }
+
+ unowned string xml_string = (string) message.response_body.data;
+
+ var collection = new MediaCollection.from_string (xml_string);
+ this.playlist_handler = new PlaylistHandler (collection, this);
+ }
}
diff --git a/src/librygel-renderer/rygel-playlist-handler.vala b/src/librygel-renderer/rygel-playlist-handler.vala
new file mode 100644
index 0000000..23dedcb
--- /dev/null
+++ b/src/librygel-renderer/rygel-playlist-handler.vala
@@ -0,0 +1,55 @@
+using GUPnP;
+
+internal class Rygel.PlaylistHandler : GLib.Object {
+ //private const int DEFAULT_IMAGE_TIMEOUT = 300;
+ private const int DEFAULT_IMAGE_TIMEOUT = 30;
+ public MediaCollection collection { construct; private get; }
+ public unowned AVTransport transport { construct; private get; }
+ public uint current_track { construct set; get; default = 1; }
+
+ private List<DIDLLiteItem> items;
+
+ public PlaylistHandler (MediaCollection collection,
+ AVTransport transport) {
+ Object (collection : collection, transport : transport);
+ }
+
+ public override void constructed () {
+ debug ("Playlist handler constructed");
+ this.items = this.collection.get_items ();
+ this.transport.n_tracks = items.length ();
+ this.set_track ();
+ }
+
+ public void next () {
+ this.current_track++;
+ if (this.current_track > this.items.length ()) {
+ debug ("Ignoring next, end of list: %u", this.items.length ());
+ this.current_track = this.items.length ();
+
+ return;
+ }
+
+ this.set_track ();
+ }
+
+ public void previous () {
+ this.current_track--;
+ if (this.current_track < 1) {
+ debug ("Ignoring previous, beginning of list.");
+ this.current_track = 1;
+
+ return;
+ }
+
+ this.set_track ();
+ }
+
+ public void set_track () {
+ var item = items.nth (this.current_track - 1).data;
+ var res = item.get_resources().nth (0).data;
+ this.transport.track = this.current_track;
+ this.transport.track_uri = res.get_uri ();
+ debug ("Trying to set track uri to %s", res.get_uri ());
+ }
+}
diff --git a/src/librygel-renderer/rygel-sink-connection-manager.vala b/src/librygel-renderer/rygel-sink-connection-manager.vala
index 9f76c9d..ec26edf 100644
--- a/src/librygel-renderer/rygel-sink-connection-manager.vala
+++ b/src/librygel-renderer/rygel-sink-connection-manager.vala
@@ -37,8 +37,20 @@ internal class Rygel.SinkConnectionManager : Rygel.ConnectionManager {
this.player = plugin.get_player ();
var protocols = this.player.get_protocols ();
+ this.sink_protocol_info += "http-get:*:text/xml:DLNA.ORG_PN=DIDL_S,";
+ this.sink_protocol_info += "http-get:*:audio/mpeg:DLNA.ORG_PN=MP3,";
this.sink_protocol_info +=
"http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM,";
+ this.sink_protocol_info +=
+ "http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320,";
+ this.sink_protocol_info +=
+ "http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320,";
+ this.sink_protocol_info += "http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM,";
+ this.sink_protocol_info += "http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED,";
+ this.sink_protocol_info += "http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG,";
+ this.sink_protocol_info +=
+ "http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_BL_CIF15_AAC_520,";
+
foreach (var protocol in protocols) {
if (protocols[0] != protocol) {
this.sink_protocol_info += ",";
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]