Andrew, when the non-transcoded file is played, does the renderer do any seeks (instead of just reading the whole file)? The reason I ask is that I've seen several renderers try to seek the end of the file after getting it's content length and before trying to play in which case giving it a fake length wouldn't solve the issue.
Hi bob,
In this case there were no seeks. However I can confirm that I have also frequently seen such seeks from many types of renderer (including if I recall it correctly, MC itself). I am not sure why such renderers actually do this, but my best guess is that they may be checking for metadata tags at the end of the file. However another reason could be that instead of just looking for an Accept-Ranges header, they want to test in reality whether the server can or cannot satisfy byte range seeks. (It could be that some servers provide Accept-Ranges headers but can't actually satisfy seeks -- and/or vice-versa).
In my case, if such a seek request comes in (so long as the seek target is within the hypothetical ContentLength already given), then my server always returns an HTTP 206 Partial Content response. It depends a bit on what transcoder is being used, but as a general rule I convert the byte seek into a time seek offset and ask the transcoder engine to start serving data from that point. Where (time seek offset) := (duration) X (byte seek offset) / (previously provided ContentLength). Although in the special case that the byte seek offset is very close to the end of the track I use (time seek offset) := (duration) - (5 seconds) in order to ensure that something always gets sent.
This approach seems to satisfy those renderers which do an initial seek. And it also means that if the user Control Point makes a normal UPnP seek operation (e.g. by moving the position scroll bar in MC), then the server is always able to satisfy the ensuing byte range seek request.
Note: If the server does not offer a ContentLength and/or if it does not offer Accept-Ranges and/or if it does not satisfy a byte range seek with HTTP 206, then what usually happens is that any user UPnP seek operation results in the renderer restarting playback at the beginning of the track -- which is a real PITA for most users. However if you do do these things, then such UPnP seek operations do result in the playback re-commencing at an appropriate point in the track.
Obviously such calculated time based seeks won't land in byte-perfect locations, so the client could not hope to stitch together the original byte stream from a series of partial seeks. I try to deliver my partial responses starting and ending on frame boundaries. And it seems that most renderers are quite happy with that (i.e. they stitch together at the frame level, rather than stitch together at the byte level..)
EDIT: in the meantime capfan kindly tested a new build of my DMRA which attempts to push tracks both with and without a ContentLength header. We could confirm that with the header it played fine, and without the header it failed. The renderer reported both a TransportState error via UPnP and also a message on its screen. My DMRA keeps on serving so in fact the track did play, whereas MC (correctly) stops serving the track. So we can definitely confirm that the issue is indeed the lack of ContentLength. And therefore my strong recommendation is that you address this issue in a forthcoming build based on the approach that I have described above.