Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Songcast Receiver in Java
27-02-2014, 10:41 AM
Post: #1
Songcast Receiver in Java
Hi,

I've been experimenting with the Songcast protocol on my Java MediaPlayer, at the moment I have some very rough code that will query the ohz uri to get the ohm uri and from the ohm uri I then join and start to receive the audio stream/packets.

'4F 68 6D 20 01 03 07 24 32 02 01 B9 00 00 ....'

I have some questions about the Songcast audio stream:

Is the Songcast audio stream always in the same format, or could the format change?

What is the Songcast audio format, is it propriety, or is it in a 'standard' format.

But the main question is not really an OpenHome question, the documentation is very good (http://openhome.org/wiki/Av:Developer:Songcast:Ohm), what I am stuck on now is how to play back the audio stream.

In my MediaPlayer I use either MPD (or mplayer) to play back the Playlist tracks and Radio steams, so I was thinking that maybe I could parse my Songcast audio stream to a format that MPD or mplayer would understand, or the other option would be to try and playback through the hardware directly, but this seems a bit limited with Java..

Has anyone done anything similar,or have any ideas how I could playback the Songcast stream.

Thanks,

Pete.
Find all posts by this user
28-02-2014, 04:07 PM (This post was last modified: 28-02-2014 05:07 PM by simonc.)
Post: #2
RE: Songcast Receiver in Java
(27-02-2014 10:41 AM)PeteManchester Wrote:  Hi,

I've been experimenting with the Songcast protocol on my Java MediaPlayer, at the moment I have some very rough code that will query the ohz uri to get the ohm uri and from the ohm uri I then join and start to receive the audio stream/packets.

'4F 68 6D 20 01 03 07 24 32 02 01 B9 00 00 ....'

I have some questions about the Songcast audio stream:

Is the Songcast audio stream always in the same format, or could the format change?

Any Songcast stream will follow the protocol spec you link below. The only circumstances in which the format would change would be if the version number (byte #5 of each packet) changes.

(27-02-2014 10:41 AM)PeteManchester Wrote:  What is the Songcast audio format, is it propriety, or is it in a 'standard' format.

Probably somewhere in between... The format is open; we've published the protocol spec and a sample implementation. Anyone is free to use it; there is no requirement to pay royalties or have your implementation approved/certified. This will be enough for some people to view it as a standard. The one thing that may cause others to disagree is that it hasn't been formally certified by e.g. IETF. There are no plans to pursue this more formal type of standardisation.

(27-02-2014 10:41 AM)PeteManchester Wrote:  But the main question is not really an OpenHome question, the documentation is very good (http://openhome.org/wiki/Av:Developer:Songcast:Ohm), what I am stuck on now is how to play back the audio stream.

In my MediaPlayer I use either MPD (or mplayer) to play back the Playlist tracks and Radio steams, so I was thinking that maybe I could parse my Songcast audio stream to a format that MPD or mplayer would understand, or the other option would be to try and playback through the hardware directly, but this seems a bit limited with Java..

Has anyone done anything similar,or have any ideas how I could playback the Songcast stream.

The audio is transmitted as big endian PCM. The ohSongcast repo includes code that parses audio packets; you could easily use this to extract the PCM data. If you don't have access to a codec that'll just pass through PCM (or possibly convert endianess), you could create a stream in WAV file format - all that'd be required here would be to write out a simple header then read PCM data from each packet, passing it on as if it were the next chunk of WAV data.
Find all posts by this user
04-03-2014, 04:40 PM (This post was last modified: 04-03-2014 04:40 PM by simoncn.)
Post: #3
RE: Songcast Receiver in Java
(28-02-2014 04:07 PM)simonc Wrote:  If you don't have access to a codec that'll just pass through PCM (or possibly convert endianess), you could create a stream in WAV file format - all that'd be required here would be to write out a simple header then read PCM data from each packet, passing it on as if it were the next chunk of WAV data.

For a WAV stream, It would be necessary to convert each sample from big-endian to little-endian format.
Find all posts by this user
04-03-2014, 04:52 PM
Post: #4
RE: Songcast Receiver in Java
(04-03-2014 04:40 PM)simoncn Wrote:  
(28-02-2014 04:07 PM)simonc Wrote:  If you don't have access to a codec that'll just pass through PCM (or possibly convert endianess), you could create a stream in WAV file format - all that'd be required here would be to write out a simple header then read PCM data from each packet, passing it on as if it were the next chunk of WAV data.

For a WAV stream, It would be necessary to convert each sample from big-endian to little-endian format.

I think it might be possible to note that audio data is big-endian by starting the stream with the bytes {'R', 'I', 'F', 'X'} (as opposed to the more usual {'R', 'I', 'F', 'F'}). Converting to little endian is probably better though as it'll be more widely supported (and also doesn't rely on my interpretation of vaguely worded docs.)
Find all posts by this user
04-03-2014, 05:21 PM
Post: #5
RE: Songcast Receiver in Java
(04-03-2014 04:52 PM)simonc Wrote:  I think it might be possible to note that audio data is big-endian by starting the stream with the bytes {'R', 'I', 'F', 'X'} (as opposed to the more usual {'R', 'I', 'F', 'F'}). Converting to little endian is probably better though as it'll be more widely supported (and also doesn't rely on my interpretation of vaguely worded docs.)

I think that would be sensible. According to this page, RIFX isn't widely supported. For example, MinimServer doesn't read RIFX files, and no-one has ever asked me to support this.
Find all posts by this user
04-03-2014, 05:48 PM
Post: #6
RE: Songcast Receiver in Java
Thanks for the detailed answer...

As usual the answer turned out to be quite simple, I used the javax.sound library to play the PCM.

It seems to be working quite well..

Thanks again,

Pete.
Find all posts by this user
14-03-2014, 05:19 PM
Post: #7
RE: Songcast Receiver in Java
Hi Sorry, another question.

The Songcast Receiver works very well when using either the OpenHome or Linn Soncast Sender for windows, but we have been testing with a Linn DS as the Songcast Sender and are having some issues.

The issues are mostly around 24bit tracks,

In the OHU audio message we are told the track is 24bit

Code:
2014-03-14 16:52:24,183 [OHMMessageQueue] INFO  [org.rpi.songcast.ohm.OHMEventAudio] Songcast Stream: Codec: ALAC SampleRate: 96000 BitRate: 4608000 BitDepth: 24
2014-03-14 16:52:24,228 [OHMMessageQueue] INFO  [org.rpi.songcast.core.SongcastPlayerJSLatency] Creating Audio Format: SampleRate:96000.0 BitRate:4608000 BitDepth:24 Channels:2 Codec:ALAC Signed:true BigEndian:true
2014-03-14 16:52:24,247 [OHMMessageQueue] DEBUG [org.rpi.songcast.core.SongcastPlayerJSLatency] FrameSize: 6
2014-03-14 16:52:24,253 [OHMMessageQueue] DEBUG [org.rpi.songcast.core.SongcastPlayerJSLatency] Adjusted Buffer Size: 31998
2014-03-14 16:52:24,268 [OHMMessageQueue] DEBUG [org.rpi.songcast.core.SongcastPlayerJSLatency] PCM_SIGNED 96000.0 Hz, 24 bit, stereo, 6 bytes/frame, big-endian

But in the meta data we are told the track is 16bit

Code:
2014-03-14 16:53:40,274 [OHMMessageQueue] DEBUG
[org.rpi.songcast.ohm.OHMEventTrack] MetaData:
<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">
    <item id="0$:Quality$1$albums$1$0" parentID="0$:Quality$1$albums$1"
        restricted="1">
        <dc:title xmlns:dc="http://purl.org/dc/elements/1.1/">Pazzo Il Mondo !?</dc:title>
        <upnp:genre xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">Musical</upnp:genre>
        <dc:date xmlns:dc="http://purl.org/dc/elements/1.1/">2008-01-01</dc:date>
        <upnp:album xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">55\21</upnp:album>
        <upnp:artist xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">Musica Nuda</upnp:artist>
        <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Musica Nuda</dc:creator>
        <upnp:originalTrackNumber xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">1
        </upnp:originalTrackNumber>
        <upnp:albumArtURI xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">http://10.0.1.146:9790/minimserver/*/Music/ALAC/Musica*20Nuda/Musica*20Nuda*20-*2055*2021*20(2008)/01*20Musica*20Nuda*20-*20Pazzo*20Il*20Mondo*20!*ef*80*a5.m4a/$!picture-8877-95049.jpg
        </upnp:albumArtURI>
        <res duration="0:02:32.000" size="14772199" bitsPerSample="16"
            sampleFrequency="44100" nrAudioChannels="2"
            protocolInfo="http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=0170000000000000000000​0000000000">http://10.0.1.146:9790/minimserver/*/Music/ALAC/Musica*20Nuda/Musica*20Nuda*20-*2055*2021*20(2008)/01*20Musica*20Nuda*20-*20Pazzo*20Il*20Mondo*20!*ef*80*a5.m4a
        </res>
        <upnp:class xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/">object.item.audioItem.musicTrack
        </upnp:class>
    </item>
</DIDL-Lite>

When we try to play the track using javax.sound we set the format according to the OHU message (24bit) but we get an error when trying to write out audio byte array.

Code:
2014-03-14 16:53:40,593 [SongcastPlayerJavaSoundLatency] ERROR [org.rpi.songcast.core.SongcastPlayerJSLatency] Error Writing Data
java.lang.IllegalArgumentException: illegal request to write non-integral number of frames (880 bytes, frameSize = 6 bytes)
    at com.sun.media.sound.DirectAudioDevice$DirectDL.write(DirectAudioDevice.java:731)​
    at org.rpi.songcast.core.SongcastPlayerJSLatency.addData(SongcastPlayerJSLatency.ja​va:99)
    at org.rpi.songcast.core.SongcastPlayerJSLatency.run(SongcastPlayerJSLatency.java:1​69)
    at java.lang.Thread.run(Thread.java:724)

Is there some kind of upscaling heppening on the Linn DS, that would make sense, that the meta data has information about the original track and the songcast has information about the upscaled stream from songcast.

On non 24bit tracks everything seems fine, even though the codec is described as non PCM (mpd, alac).

Thanks,

Pete.
Find all posts by this user
14-03-2014, 05:56 PM
Post: #8
RE: Songcast Receiver in Java
(14-03-2014 05:19 PM)PeteManchester Wrote:  When we try to play the track using javax.sound we set the format according to the OHU message (24bit) but we get an error when trying to write out audio byte array.

Code:
2014-03-14 16:53:40,593 [SongcastPlayerJavaSoundLatency] ERROR [org.rpi.songcast.core.SongcastPlayerJSLatency] Error Writing Data
java.lang.IllegalArgumentException: illegal request to write non-integral number of frames (880 bytes, frameSize = 6 bytes)
    at com.sun.media.sound.DirectAudioDevice$DirectDL.write(DirectAudioDevice.java:731)​
    at org.rpi.songcast.core.SongcastPlayerJSLatency.addData(SongcastPlayerJSLatency.ja​va:99)
    at org.rpi.songcast.core.SongcastPlayerJSLatency.run(SongcastPlayerJSLatency.java:1​69)
    at java.lang.Thread.run(Thread.java:724)

Is there some kind of upscaling heppening on the Linn DS, that would make sense, that the meta data has information about the original track and the songcast has information about the upscaled stream from songcast.

On non 24bit tracks everything seems fine, even though the codec is described as non PCM (mpd, alac).

Thanks,

Pete.

For 24-bit audio, a stereo sample is 6 bytes long. You are trying to write 880 bytes, which doesn't correspond to an integral number of 6-byte samples.
Find all posts by this user
14-03-2014, 05:59 PM (This post was last modified: 14-03-2014 05:59 PM by simonc.)
Post: #9
RE: Songcast Receiver in Java
Other than eventing it to subscribers and sending it via songcast, the DS does not use the metadata that a control point provides. You can trust the bit depth in the songcast frames and ignore the one in metadata.

Audio data in songcast frames will be packed big endian pcm. I think it should always contain audio for an exact number of samples. In normal use, you'd expect each frame to contain 5ms of audio. For 24-bit 96kHz stereo this'd equate to 2880 bytes of audio per frame. Can you recheck the code that is reporting 880 bytes please?
Find all posts by this user


Forum Jump: