|
|
|
Know what your not good at, and don't do it
|
1/30/2010 2:57:25
|
So these past couple weeks I have continued to hack with Python+GUPnP via PyGI. I've pushed some important patches lately, and have even begun making progress in getting the biggest components of my work upstream (woohoo!. GUPnP-AV, GSSDP have been merged. GUPnP itself is 80% the way there, and PyGI is in review).
So, where do I stand on AutoRemote/Zhaan? Zhaan hasn't gotten any love lately and is actually using some older code that I have replaced with much nicer libraries inside AutoRemote.
So, most of my time has gone into AutoRemote (what a crappy name). I am at the point where the UI needs to be written. So I wrote some of it. And its REALLY ugly. And HORRIBLE to use. And I did NOT enjoy writing it. I am happy to say I can recognize what is good UI and what is bad UI, but my own skills to design (and implement!) that good UI apparently don't exist. I think I just proved that P != NP. Awesome.
-Zach Goldberg
|
|
|
|
|
It's Alive -- MPD + UPnP
|
12/22/2009 10:30:57
|
I've put together a (working) quick and dirty script to wrap MPD in a UPnP Media Renderer. This is far from a complete solution, but it allows playing/pausing via UPnP Control Points. (Python-GUPnP CP works just dandy for it!)
from gi.repository import GUPnP, GObject, GLib import mpd
CON_ID = None MPDCLIENT = None
GObject.threads_init()
def setup_server():
ctx = GUPnP.Context(interface="eth0")
ctx.host_path("device.xml", "/device.xml") ctx.host_path("AVTransport2.xml", "/AVTransport2.xml")
desc = "device.xml" desc_loc = "./"
rd = GUPnP.RootDevice.new(ctx, desc, desc_loc) rd.set_available(True)
return rd
def setup_mpd(): global CON_ID, MPDCLIENT HOST = 'localhost' PORT = '6600' CON_ID = {'host':HOST, 'port':PORT}
MPDCLIENT = mpd.MPDClient()
def on_play_action(service, action): print "Play" MPDCLIENT.connect(**CON_ID) MPDCLIENT.play() MPDCLIENT.disconnect()
def on_pause_action(service, action): print "Pause" MPDCLIENT.connect(**CON_ID) MPDCLIENT.pause() MPDCLIENT.disconnect()
rd = setup_server() print "UPnP MediaRenderer Service Exported"
setup_mpd() print "MPD Client Setup"
service = rd.get_service("urn:schemas-upnp-org:service:AVTransport:1") service.connect("action-invoked::Play", on_play_action) service.connect("action-invoked::Pause", on_pause_action)
print "Awaiting commands..." GObject.MainLoop().run()
Update: This is an updated version of the script that supports more commands and properly ends each UPnP action. Unfortunately it doesn't entirely work because of either 1) A bug in g-i or 2) a problem with the gupnp api that will require a break to fix. Spent a lot of time today to understand the problem, hopefully we'll have either a gupnp or a g-i fix in a few days.
Update 2: Now available on github. Zhaan (formerly known as "GUPnP-Python UPnP Control Point" has also been pushed)
-Zach Goldberg
|
|
|
|
|
Pondering MPD and UPnP
|
12/21/2009 9:50:24
|
I had the idea tonight to try and get MPD to act as a well behaved UPnP MediaServer. Low and behold, there exists python-mpd. I smell a new use for GUPnP-Python in the next few days :)
-Zach Goldberg
|
|
|
|
|
GUPnP-Python Control Point Progress
|
12/20/2009 10:50:08
|
Just a brief update. The control point has been making steady progress. I've tested it with a bunch more servers/renderers and its doing fairly well as far as compatibility goes. I've also finished up basic playlist management and some UI quirks (like adding scrollbars).
Next step is to port this guy to Maemo 5 and Hildon-GTK :)
-Zach Goldberg
|
|
|
|
|
Rygel ogg transcoding and the Playstation 3
|
12/20/2009 10:34:03
|
Zeeshan was rather angry at me for putting so much effort into Mediatomb (and rightfully so), so I figure'd I would make him happy and try out Rygel.
Short Summary: Some things work REALLY well (MUCH better than Mediatomb), some things not so well yet. (afterall, Rygel is under much more active development than Mediatomb so any of my gripes could likely be fixed in the near future)
The first problem was getting an up to date version of Rygel. Gstreamer inside jhbuild decided it wasn't interested in loading any of its plugins. Rygel, outside of jhbuild, decided that none of its dependencies would build properly.
It took me 1.5 hours just to get a working version of Rygel compiled. Lame. This, however, would be mitigated by a recent Rygel release and just installing from .deb. So no real marks against Rygel for that.
I then configured Rygel with 2 "Media Exports". My music folder and my movies folder. It then proceeded to spent 15 minutes at 100% CPU scanning my movies.
And it forgot my music :(.
After the initial 15 minutes Rygel crashed because I was missing some gstreamer plugin (shouldn't configure have found that?). Fixed that and rygel finally shows up on the network.
I re-added my music directory without a symlink and this time Rygel loaded it all fine. *shrug*.
I ran over to the PS3 once Rygel had the music categorized and found that, indeed, the PS3 could browse Rygel's collection (to a certain extent... it got an error loading past the 30th item in the list or so. Still trying to find that bug). Anyway, the major point: transcoding worked out of the box for music. No mess, no fuss. Seeking in transcoded streams also worked out of the box. SWEET!
Movies, however, were a different story. I couldn't get any movies to play at all off of Rygel on the PS3. They did, however, work locally when manipulated by my gupnp-python control point.
The one other issue I have is that Rygel doesn't auto-generate folders for meta-browsing like media tomb did. Media tomb would scan all my music and generate some folders such as "Albums" and "Artists" and "All Music" (good for a random playlist) which I could browse on the PS3. No such feature in Rygel yet. (Although the devs say they are open to adding it. Apparently it also works if I use the Tracker plugin. Sadly, however, I don't use tracker on my server).
Overall, the Rygel guys get an A+ for awesome transcoding support for music. The movies issue could also just be a recent bug, as with the showing all items in a large list bug. (Zeeshan says these things should work, so it could just be a regression. I am using git HEAD after all.) I'll also chalk the lack of the meta-folder feature to Rygel still being relatively new software.
Overall very promising. If Rygel didn't have those few bugs mentioned above it would have already replaced Mediatomb and made me a very happy camper. I suspect that these bugs will be fixed shortly and I expect to switch soon :)
-Zach Goldberg
|
|
|
|
|
Mediatomb ogg transcoding and the Playstation 3
|
12/18/2009 2:10:51
|
(My most astute readers will notice that this is being posted after 5AM in the morning Eastern. My web server is on the west coast so it says 2 but don't be fooled! No I did not just wake up, I've been hacking on this for the past 4 hours.)
I bought a PS3 several months ago to act as, among other things, a UPnP Media Renderer (although not by the real technical definition... its more of a gimped control point that can render locally... but thats a gripe for another day). I've known since I started using it that the PS3 was only picking up the MP3 songs from my Mediatomb server. I decided that it was time to fix this.
No matter what got in the way.
I knew mediatomb was capable of doing on the fly transcoding (as any good server is, Rygel can too!) so I figured I would play with those settings. This is where we had the first bad omen -- to configure it I needed to copy some XML from a gentoo wiki doc. Oh boy, bad sign.
Of course it doesn't work at first. Hell, the oggs don't even show up! Some flacs do though, so I decide i'll try and tackle making the flacs work first and then work on making the oggs show up.
1.5 hours go by. Transcoding works fine if i pull the URL by hand and run it in mplayer but the ps3 is stubborn. It is at this point that I notice that mediatomb has a DNLA non-compliance issue in 0.11 which causes the ps3 to not be able to pick up transcoded media. Go figure! Now... wait.... version 0.12 has the fix but... its been 2 years and 0.12 isn't out... time to compile from source! Sigh.
10 minutes later I have mediatomb "0.12" (aka SVN HEAD) installed and ready to go.
Yay! This time it looks like its trying to actually transcode the flac, (e.g. the ps3 doesnt immediatly bail out with a non-compatible error) but I do get just static. I messed with some things and I thought I had it working so I moved on to getting oggs to show up.
Now, in the mediatomb configuration itself oggs are classified as "application/ogg" (not audio/ogg for some reason) and the upnp_class for musicTrack is only for audio/* so I thought that was fishy. I did some poking and prodding using Zeeshan's fantastic gupnp-universal-cp and some custom GUPnP-Python scripts (woot!) to investigate. Turns out my ogg files are getting the wrong UPnP Class! They are showing up as object.item instead of object.item.music.musicTrack (or something like that).
I patch up the config to change things to be mime-type "audio/ogg" instead of "application/ogg" and... bupkis. Turns out (after another 30 minutes of poking) that mediatomb stores the upnp class and mime type hardcoded inside its database. Sure, why not? Lets just dump the whole thing! So I did, and had mediatomb rescan all my media with the new mime-types for ogg.
Low and behold now my gupnp-universal-cp shows oggs with the right class AND they show up in the PS3!
We're not out of the woods yet! Remember when I said I *thought* I had flacs playing correctly before? I was wrong. The music was somehow playing at half speed (what the heck?). Well, this is a purely transcoding issue so I dove into the transcoding script. I confirmed that its the exact same thing the gentoo wiki had, yet still my media played at half speed.
Well... one fix for that is to simply half the frequency at the encoder, right? So i did, I told ffmpeg to output 22050 instead of 44100hz and magically everything sounds right!
Whew! And to think, in the 4 hours all that took I probably could've converted my 1500 or so flac + oggs to mp3s.
In the end though, I am not angry. I think its awesome that I am able to debug this at such a low level and have it work at the end of the day. But lets think about the things I had to fix:
- "Add" the config to mediatomb's config
- "Upgrade" my mediatomb version
- Application/ogg -> audio/ogg in mediatomb's config
- "fix" the transcoding script that i got from the gentoo wiki
Not that much, right? And none of those are really big changes. If Mediatomb simply shipped with sane defaults (audio/ogg) and an easy option to enable the transcoding configuration (instead of my having to copy and paste it in) this would have worked out of the box. I believe this is a very common problem in Linux. The basics work out of the box fine, but the VAST potential for extra AWESOME features is not accessible to the average user because we are simply too poor at unlocking those capabilities with sane defaults and reasonable configurability.
I hope this helps some other user figure out how to get transcoding with mediatomb/ps3 working and maybe even motivate a developer or two to perhaps ship these configs in working, sane, form so some other user won't even have to google for this post.
p.s. If you do end up mucking around with this and are trying to get the transcoding just right, take my advice: Stick with pcm_s16be. Nothing else works, I tried.
-Zach Goldberg
|
|
|
|
|
Python GUPnP as a Working control point
|
11/28/2009 3:2:00
|
Greetings!
In my last post I wrote about some success sending actions via python + GUPnP. Its been less than a week since then and I can now report that nearly everything needed for a control point works in Python + GUPnP... I know this because in the time it took my to take a bus from Philadelphia to NYC I wrote one :). It uses the following UPnP Features:
1) Downloading Icons from other devices 2) ASync sending actions 3) Async retrieving data from actions 4) Parsing DIDL's and DIDLItem, DIDLContainer and DIDLResource objects using GUPnP-AV and more..
I unfortunately am about to run out, but I'll tease you with this (conveniently... *wink wink*) 800x480 screenshot.

-Zach Goldberg
|
|
|
|
|
GUPnP + Gobject Introspection Status
|
11/21/2009 6:54:07
|
As I've been mentioning lately I have been working on using PyGObject + GObject Introspection (recently forked, now called PyGI + PyGObject + Gobject Introspection) and have some exciting news!
I have been working on fleshing out a whole bunch of unit tests which exercise the entire GUPnP API. I hate a major roadblock in that PyGI did not support native callbacks! So, after a week or two detour I have implemented PyGI callbacks (which now work rather nicely, but need a bunch of stylistic cleanups and error checking before its pushed back upstream.. priorities!) as well as some working GUPnP demos.
My best demo so far is about 25 lines of python which:
1) Gets all devices on one network interface 2) Scans for all the services each device provides 3) If the device is GMediaRenderer and it provides an AVTransport Service (it does...) then it 3a) Stops whatever is currently playing 3b) Loads a new URI (hardcoded from my mediatomb server for now, havn't played enough with gupnp-av to dynamically get the mediatomb data -- for now!) 3c) Initiates playing
3a->3c have been tested using the synchronous GUPnP action api (send_action...) as well as the asynchronous API (begin_action.... end_action...) with callbacks!
-Zach Goldberg
|
|
|
|
You are free to redistrubute
this material under the terms of the Creative Commons Share-alike license as long as
there is appropriate attribution back to zachgoldberg.com
|
|