Hello Twonky! This is Europe calling.

I’m still looking at getting the album order correct on multi-disc albums. Only now, I’m running Twonky on my T12-423 rather than the WD NAS so I can pretty much do what I want to now.

So, first things first. The Twonky calls.

I’m using HTTPie but Postman would be equally good. First, we need to construct a post to read the available albums:

POST http://192.168.3.16:9000/dev0/srv1/control

<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
<ObjectID>0$1$12</ObjectID>
<BrowseFlag>BrowseDirectChildren</BrowseFlag>
<Filter>*</Filter>
<StartingIndex>233</StartingIndex>
<RequestedCount>300</RequestedCount>
<SortCriteria/>
</u:Browse>
</s:Body>
</s:Envelope>

I can’t remember where the original object ID comes from (a thing for another day) but the StartingIndex and the RequestedCount are where you want to start in your list of albums and how many albums you’d like returned. Twonky only seemed to return 232 which is why I started at 233. I deliberately kept the RequestCount High because Twonky will tell me how many entries its retuned so I’m not too fussed about being accurate.

Twonky returns coded XML which looks like this:

<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/" xmlns:arib="urn:schemas-arib-or-jp:elements-1-0/" xmlns:dtcp="urn:schemas-dtcp-com:metadata-1-0/" xmlns:pv="http://www.pv.com/pvns/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"><container id="0$1$12$4282" parentID="0$1$12" restricted="1" childCount="38" searchable="1"><dc:title>Eurovision Song Contest 2014: Copenhagen - Join Us</dc:title><upnp:genre>Pop</upnp:genre><upnp:album>Eurovision Song Contest 2014: Copenhagen - Join Us</upnp:album><dc:creator>Various Artists</dc:creator><upnp:albumArtURI dlna:profileID="JPEG_TN" >http://192.168.3.16:9000/disk/DLNA-PNJPEG_TN-OP01-CI1-FLAGS00d00000/defaa/C/O0$1$12$4282.jpg?scale=org</upnp:albumArtURI><pv:childCountContaine

Copy the body into SublimeText and find / replace the &lt; and &gt; with < and > respectively, then indent the XML to get a nicely formatted page. From this I can easily see that the object for Eurovision 2024 is:

<container childCount="37" dc:date="2024-01-01T12:00:00" id="0$1$12$5307" parentID="0$1$12" restricted="1" searchable="1">
<dc:title>Eurovision Song Contest 2024: Malmö - United By Music</dc:title>
<dc:date>2024-01-01</dc:date>
<upnp:genre>Pop</upnp:genre>
<upnp:album>Eurovision Song Contest 2024: Malmö - United By Music</upnp:album>
<dc:creator>Various Artists</dc:creator>
<upnp:albumArtURI dlna:profileID="JPEG_TN">http://192.168.3.16:9000/disk/DLNA-PNJPEG_TN-OP01-CI1-FLAGS00d00000/defaa/C/O0$1$12$5307.jpg?scale=org</upnp:albumArtURI
<pv:childCountContainer>0</pv:childCountContainer>
<upnp:artist>Various Artists</upnp:artis>
<pv:modificationTime>421989616</pv:modificationTime><pv:containerContent>object.item.audioItem.musicTrack</pv:containerContent>
<upnp:class>object.container.album.musicAlbum</upnp:class>
</container>

Now, make a call to Twonky using the same parameters as the CXN makes:

POST http://192.168.3.16:9000/dev0/srv1/control
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
<ObjectID>0$1$12$5307</ObjectID>
<BrowseFlag>BrowseDirectChildren</BrowseFlag>
<Filter>dc:title,upnp:class,upnp:album,upnp:originalTrackNumber,id,res,res@protection,res@duration,upnp:searchClass,upnp:artist,upnp:genre,upnp:albumArtURI</Filter>
<StartingIndex>0</StartingIndex>
<RequestedCount>100</RequestedCount>
<SortCriteria>+upnp:originalTrackNumber,+dc:title</SortCriteria>
</u:Browse>
</s:Body>
</s:Envelope>

This returns:

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:BrowseResponse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
<Result>
<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/" xmlns:arib="urn:schemas-arib-or-jp:elements-1-0/" xmlns:dtcp="urn:schemas-dtcp-com:metadata-1-0/" xmlns:pv="http://www.pv.com/pvns/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">
<item id="0$1$12$5307R891915" parentID="0$1$12$5307" restricted="1">
<dc:title>Hurricane [Israel]</dc:title>
<upnp:genre>Pop</upnp:genre>
<upnp:album>Eurovision Song Contest 2024: Malmö - United By Music</upnp:album>
<upnp:originalTrackNumber>1</upnp:originalTrackNumber>
<upnp:albumArtURI dlna:profileID="JPEG_TN" >http://192.168.3.16:9000/disk/DLNA-PNJPEG_TN-OP01-CI1-FLAGS00d00000/defaa/A/O0$1$8I891915.jpg?scale=org</upnp:albumArtURI>
<upnp:artist>Eden Golan</upnp:artist>
<res duration="0:03:01.440" protocolInfo="http-get:*:audio/x-aiff:*" >http://192.168.3.16:9000/disk/NON-DLNA-OP01-FLAGS01700000/O0$1$8I891915.aif</res>
<upnp:class>object.item.audioItem.musicTrack</upnp:class>
</item>
<item id="0$1$12$5307R887307" parentID="0$1$12$5307" restricted="1">
<dc:title>Titan [Albania]</dc:title>
<upnp:genre>Pop</upnp:genre>
<upnp:album>Eurovision Song Contest 2024: Malmö - United By Music</upnp:album>
<upnp:originalTrackNumber>1</upnp:originalTrackNumber>
<upnp:albumArtURI dlna:profileID="JPEG_TN" >http://192.168.3.16:9000/disk/DLNA-PNJPEG_TN-OP01-CI1-FLAGS00d00000/defaa/A/O0$1$8I887307.jpg?scale=org</upnp:albumArtURI>
<upnp:artist>BESA</upnp:artist>
<res duration="0:02:58.226" protocolInfo="http-get:*:audio/x-aiff:*" >http://192.168.3.16:9000/disk/NON-DLNA-OP01-FLAGS01700000/O0$1$8I887307.aif</res>
<upnp:class>object.item.audioItem.musicTrack</upnp:class>
</item>

Hurricane is not the first track for the album so this is obviously wrong.

As I can’t change what the CXN is asking for, I need to change the response the CXN is receiving (if that is even possible?)

What I think I need to do is to have the “upnp:originalTrackNumber” be a combination of the disc number and the actual track number so it becomes something like 101 and 201 for the first track on the first and second disks… I think I’m out of luck there.

Fun with the Cambridge Audio CXN-v2

Buckle up, this is a ride.

First off, I have to say that I do love the Cambridge Audio kit, I’ve not got anything fancy, just a CXA-60, a CXN(v2), a CXN and a pair of SX-60s. I’ve been after some Cambridge Audio separates for ages since I originally saw them in Richer Sounds many years ago. When my small Panasonic network player died it was more costly to get it fixed than to buy a new one and, since it was cheaper to buy a new one, I just went for the CXA-60 and the CXN(v2) and kept the speakers I had. The Cambridge Audio stuff does sound truly fabulous and properly love it.

There’s just one (smallish) problem.

I use iTunes to rip all my media and Meta to keep the data tidy. The back end storage is a WD My Cloud Mirror Gen 2 running Twonky 8.1. Twonky isn’t perfect and sometimes it needs a helping hand to properly recognise all album tracks but I really like the sort order it uses and it’s pretty useful for media management.

Most discs tend to have data something like:

The Title, Track Number and Disc Number are the important fields.

With most albums the tracks play in the order they’re expected to, track 1, track2 track 3 etc.

However, there is a bit of a problem with multi-disc albums. For some reason the play order is not set. Sometimes track 1, disc 1 plays first and sometimes track 1 disc 2 plays first. The play order is always alphabetic. So, really, the sort order for multi-disc albums is track number followed by alphabetic sorting of the resultant list. For albums that have two discs this is irritating because the play order is completely out of sequence, for compilations that have around five discs this is a nightmare.

Because I’d given feedback on the Cambridge Audio app I was given the opportunity to do some beta testing with the new app. Naturally, I gave that a go.

One of the things I noticed was that the app displayed a different sort order to the CXN for multi-disc albums (the proper order) but when the album was played via the app the actual play order was different from the displayed play order. That was kind of annoying really.

Investigating things further I used my LG TV do navigate the album structure to see if the same problem occurred there too. The LG TV doesn’t play AIFF files though so, as far as the TV was concerned, there was no content in any of the directories I was looking at. I had to convert all the AIFF files to MP4 files and then the TV could see the files. Not only could the TV see the files but they were displayed and played in the correct order too. To my mind, this meant that the CXN was not asking for the disc number when generating a list of assets to play.

After much back-and-forth with Cambridge Audio support I managed to get the developers to take a look at the problem. The upshot there is that as the albums play correctly when played through a USB stick and other NAS (Synology in this case) there must be a problem with the WD NAS and the way it presents its data. I’m completely not convinced that is the case because the LG TV plays everything correctly and if there was a problem with the NAS that could not happen.

At this point I was thinking I should just buy a new NAS, especially as a disk has died in the WD one, but I’m just too stubborn to give up like that and, although I can’t seem to generate DLNA traffic, I wondered whether it would be possible to snoop the traffic between the CXN and the NAS. Turns out it totally is. I mirrored the NAS port and used my Mac to read all the traffic. Using a packet capture of:

tcpdump -i en5 port 9000 host wdmycloudmirror.local -XAvvv -w cxn.cap --print

Using Wireshark I managed to filter out the HTTP traffic and I could see that when the request came for the album details it looked like this:

<?xml version="1.0" ?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
			<ObjectID>0$1$12$18640</ObjectID>
			<BrowseFlag>BrowseDirectChildren</BrowseFlag>
			<Filter>dc:title,upnp:class,upnp:album,upnp:originalTrackNumber,id,res,res@protection,res@duration,upnp:searchClass,upnp:artist,upnp:genre,upnp:albumArtURI</Filter>
			<StartingIndex>0</StartingIndex>
			<RequestedCount>100</RequestedCount>
			<SortCriteria>+upnp:originalTrackNumber,+dc:title</SortCriteria>
		</u:Browse>
	</s:Body>
</s:Envelope>


Here it’s pretty easy to see that the sorting requested by the CXN is:

+upnp:originalTrackNumber,+dc:title

So it’s not asking for the disc number at all. The same request from the app looks like this:

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
			<ObjectID>0$1$12$18640</ObjectID>
			<BrowseFlag>BrowseDirectChildren</BrowseFlag>
			<Filter>*</Filter>
			<StartingIndex>0</StartingIndex>
			<RequestedCount>100</RequestedCount>
			<SortCriteria/>
		</u:Browse>
	</s:Body>
</s:Envelope>

Again, here it’s pretty easy to see that no sorting has been applied to the results. Also, no filtering has been applied to the original request either.

Now, not being a software developer I’m only making a suggestion here but I reckon that adding +pv:numberOfThisDisc to the filtering and sorting of the CXN requests would completely fix the problem with multi-disc albums. I’ve suggested that but it’s out of my hands and I just have to hope that my proposal is accepted…