AES67 sender pipeline options

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

AES67 sender pipeline options

James Cowdery
This post was updated on .
I've put together an audio pipeline to stream a wav file that will be readily
accepted by AES67 compatible receivers e.g. Ravenna or Dante. I also send
out the SDP using a SAP packet separately.

 * .------------.      .----------.      .--------------.      .------------.      .-----------.         .---------.
 * |multifilesrc|     |wavparse|     |audioconvert|      |rtpL16pay|      | rtpbin    |         |udpsink|  RTP
 * |              src->sink      src->sink              src->sink    src->recv_rtp   send_rtp->sink       | port=5004
 * '------------'       '-----------'     '---------------'     '------------'      |              |          '--------'
 *                                                                                               |              |      
 *                                                                                               |              |           .---------.
 *                                                                                               |              |           |udpsink|  RTCP
 *                                                                                               |        send_rtcp->sink       | port=5005
 *    .-----------.                                                    .--------.          |              |            '---------'
 *    |ptp-clock|                                       RTCP      | udpsrc |        |              |
 *    '-----------'                                 port=5005    |         src->recv_rtcp      |                      
 *                                                                        '---------'          '-----------'              

This works fine for receivers that are not ptp locked e.g. ffplay but my
Ravenna receiver complains about the RTP timestamps being too late or not
synchronized to PTP.
I've created the PTP clock which appears to lock to my PTP grandmaster OK
and I execute gst_pipeline_use_clock to lock the pipeline to the PTP clock
once it's synched. However, I think I need to set a few options to get the
timestamps correct. The options I'm unsure about are:

rtpbin.buffer-mode
rtpbin.ntp-time-source
pipeline latency (gst_pipeline_set_latency)
rtpL16pay.timestamp-offset

There may be others that are important. Can anyone tell me what settings I
need to get the outgoing timestamps correct with respect to the PTP clock?
Thanks,
James

--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
gstreamer-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: AES sender pipeline options

Sebastian Dröge-3
Hi James,

On Thu, 2019-01-24 at 13:06 -0600, James Cowdery wrote:
> I've put together an audio pipeline to stream a wav file that will be readily
> accepted by AES67 compatible receivers e.g. Ravenna or Dante.

That's great to hear. When implementing all those things I focussed
mostly on GStreamer-based receivers but in theory this should also work
for senders, and a colleague of mine also got it to work with Dante a
while ago.

>  I also send out the SDP using a SAP packet separately.

How does your SDP look like exactly? Most importantly, does it signal
the PTP clock correctly and the media clock offset (i.e. the diff
between PTP and RTP timestamps)?

gst-rtsp-server can produce RFC7273 (and thus AES67) compatible SDPs,
so maybe you can take some inspiration from that code.

>
> [...]            
>
> This works fine for receivers that are not ptp locked e.g. ffplay but my
> Ravenna receiver complains about the RTP timestamps being too late or not
> synchronized to PTP.

Can you share the exact errors you get? But my guess would be the media
clock offset in the SDP being wrong.

> I've created the PTP clock which appears to lock to my PTP grandmaster OK
> and I execute gst_pipeline_use_clock to lock the pipeline to the PTP clock
> once it's synched. However, I think I need to set a few options to get the
> timestamps correct. The options I'm unsure about are:
>
> rtpbin.buffer-mode
> rtpbin.ntp-time-source
> pipeline latency (gst_pipeline_set_latency)

These ones don't matter at all for senders.

> rtpL16pay.timestamp-offset

This is the "start" RTP timestamp to be used by outgoing packets, and
by default is randomized. You can make use of this for creating the
SDP.

In addition, the max/min-ptime properties on the payloader might be
relevant. AES67 wants specific packet sizes.

--
Sebastian Dröge, Centricular Ltd · https://www.centricular.com


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

signature.asc (981 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: AES sender pipeline options

James Cowdery
Sebastian,
Great to see your reply and thanks for your suggestions.

Here is my SDP:
v=0
o=- 123456789012345 0 IN IP4 10.202.150.191
s=my_stream
c=IN IP4 239.150.250.250/31
t=0 0
m=audio 5004 RTP/AVP 98
i=1L,1R
a=ts-refclk:ptp=IEEE1588-2008:d0-a4-b1-ff-fe-00-00-0c:0
a=mediaclk:direct=0
a=clock-domain:PTPv2 0
a=source-filter: incl IN IP4 239.150.250.250 10.202.150.191
a=rtpmap:98 L16/48000/2
a=framecount:48
a=ptime:1
a=recvonly
a=sync-time:0


I spent a bit more time on this today and I think I know what the problem
is. From the AES67 spec. (section 5), the timestamps have to derived from
the PTP clock. The timestamp is the number of audio sample periods since the
Epoch modulo 32 (24.86 hours for 48kHz).
So you have to get the time since the Epoch (1/1/70), which is your PTP
clock (GstPtpClock.ptp-time), multiply it by the sampling frequency and then
modulo 2^32 i.e. take the bottom 32 bits. I've inspected a good (Ravenna)
AES67 stream, compared the timestamps with the PTP clock and this
calculation seems to be right. I can reboot the AES67 sender and RTP
timestamps are consistent i.e. an external clock is being used for the
timestamps so that all makes sense.

Obviously the streams I've created start with a random or 0 offset so
receivers compare that with their own PTP time (mod 32) and reject the
stream when it is out of range. The error I am getting is 'packets could not
be played back because they arrived too late.'


I can't fix that with a fixed offset in the SDP because I don't know ahead
of time exactly what the value of the PTP clock will be when the first
packet goes out. All the Ravenna streams I've seen have the line
'a=mediaclk:direct=0' in the SDP so I've copied that.

Does all that make sense?
Do you agree with my assessment?
If so are the RTP payloaders able to access and use the PTP clock?

Thanks,
James




--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: AES sender pipeline options

Sebastian Dröge-3
Hi James,

On Thu, 2019-01-24 at 23:29 -0600, James Cowdery wrote:

> [...]
> I spent a bit more time on this today and I think I know what the problem
> is. From the AES67 spec. (section 5), the timestamps have to derived from
> the PTP clock. The timestamp is the number of audio sample periods since the
> Epoch modulo 32 (24.86 hours for 48kHz).
> So you have to get the time since the Epoch (1/1/70), which is your PTP
> clock (GstPtpClock.ptp-time), multiply it by the sampling frequency and then
> modulo 2^32 i.e. take the bottom 32 bits. I've inspected a good (Ravenna)
> AES67 stream, compared the timestamps with the PTP clock and this
> calculation seems to be right. I can reboot the AES67 sender and RTP
> timestamps are consistent i.e. an external clock is being used for the
> timestamps so that all makes sense.
>
> Obviously the streams I've created start with a random or 0 offset so
> receivers compare that with their own PTP time (mod 32) and reject the
> stream when it is out of range. The error I am getting is 'packets could not
> be played back because they arrived too late.'
>
> I can't fix that with a fixed offset in the SDP because I don't know ahead
> of time exactly what the value of the PTP clock will be when the first
> packet goes out. All the Ravenna streams I've seen have the line
> 'a=mediaclk:direct=0' in the SDP so I've copied that.
>
> Does all that make sense?
> Do you agree with my assessment?
Yeah, that's what I meant with the media clock offset: the
mediaclk:direct=XXXX line in the SDP.

> If so are the RTP payloaders able to access and use the PTP clock?

The way how it works in gst-rtsp-server is that the SDP is only created
when the stream itself is created. So during pipeline construction you
will exactly know the PTP time that corresponds to the very first RTP
packet that is sent out and can then calculate the media clock offset
accordingly.

An alternative would be to set the timestamp-offset property in the
payloader accordingly so that the first packet has the RTP timestamp
you expect, but that basically requires doing the same as in the first
case.

In either case, it's not the payloader's job to know the clock time
that corresponds to an RTP packet and timestamp accordingly. The
timestamping inside the payloader happens completely separate from the
clock based on the timestamp (and the running time calculated from
that) of the incoming buffers.
It is the job of the code building the pipeline to ensure that those
timestamps make sense in the GStreamer synchronization model.

So basically what you could do is when building your pipeline to catch
the very first packet/buffer that comes out of the payloader in a pad
probe. From there you can then get the PTS/running time and RTP
timestamp, can convert the running time to the corresponding clock time
when it should be rendered and based on that generate your SDP.

Or if the SDP must be static, you could do something similar before the
payloader and then based on that set the correct timestamp-offset
property so that the first RTP timestamp coming out of the payloader
would correspond to the fixed media clock offset.

--
Sebastian Dröge, Centricular Ltd · https://www.centricular.com


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

signature.asc (981 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: AES sender pipeline options

James Cowdery
Sebastian,
               Understood. I think most implementations have a custom driver
that accurately timestamps the packets on the way out based on the PTP.
However, from reading the standard it sounds like I should get away with the
increased link offset of these methods (this is not production code). I'll
start with the last method you outlined as this seems simplest and closely
matches the streams I've observed and see if I can keep my receivers happy.
Adding RTSP is future step. I need that for Ravenna support anyway as it
uses RTSP and zeroconf for discovery and SDP exchanges.

I'll return with what I found out. I think this is an interesting area for
anyone starting with gstreamer and AES67 and it would be great if some of
this work could be reused so things work more 'out of the box' or at least a
public example.
Thanks again for the help,
James



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: AES sender pipeline options

James Cowdery
In reply to this post by Sebastian Dröge-3
HI Sebastian,
        So I tried setting the timestamp-offset using a data pad probe on
the previous block to the RTP payloader so that it is set just before the
first packet enters the payloader. It seems that timestamp-offset has to be
set before the pipeline is set to run otherwise it is ineffective. What is
the easiest way around this?
I've thought of a few but they all seem complex e.g. writing a modified
payloader plugin etc.
Thanks,
James



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: AES sender pipeline options

Sebastian Dröge-3
On Tue, 2019-01-29 at 11:52 -0600, James Cowdery wrote:
> HI Sebastian,
>         So I tried setting the timestamp-offset using a data pad probe on
> the previous block to the RTP payloader so that it is set just before the
> first packet enters the payloader. It seems that timestamp-offset has to be
> set before the pipeline is set to run otherwise it is ineffective. What is
> the easiest way around this?
> I've thought of a few but they all seem complex e.g. writing a modified
> payloader plugin etc.

It should be sufficient to set it before caps negotiation happens or
maybe even before the first buffer arrives in the payloader.

You could install a pad probe on the sink pad of the payloader to get
notified about either a) the CAPS event arriving, b) the first buffer
arriving, and then set the property from there.

--
Sebastian Dröge, Centricular Ltd · https://www.centricular.com


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

signature.asc (981 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: AES sender pipeline options

James Cowdery
Sebastian,
Actually I've managed to get the starting timestamp accurate enough setting
it just before runtime. I'm now only a few hundred microseconds off. I have
an issue with timestamp behaviour though.

Interestingly the timestamps start late and there is a fast burst where the
timestamps catch up and once the rtp returns to playout speed (1 packet /
ms) the timestamps between my stream and a reference stream are almost
identical :-)
Over an entire minute the sequence number offset between the reference
stream my stream stay the same between adjacent packets (which are both 1ms)
so I believe the pipeline is indeed synched to PTP :-)
However, the timestamps do not stay locked. Every 40ms there is a marker
packet (not present in reference stream). This increments the RTP timestamp
by 96 samples instead of the normal 48 despite being a 48 sample packet like
the rest. So the stream timestamps are advancing an extra 1ms per 40ms and
the receiver obviously doesn't like it.
I think these mark packets are something to do with playout compensation but
at the moment they are throwing off the timing of my stream.
James



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: AES67 sender pipeline options

James Cowdery
In reply to this post by Sebastian Dröge-3
I see the RTPs markers are the symptom not the cause of the discontinuities.
I went back my code just before I added rtpbin and it doesn't have the
regular 40ms discontinuities. It also doesn't have the fast preroll and just
starts immediately at 1 packet per ms.
That code plays back OK with an 8ms fudge factor to get initial
timestamp-offset right.
I'll need RTCP at some point but for now I've ditched it for now and work on
getting that clean and robust.

Thanks for advice on setting the payloader timestamp offset. The method I
have working is accurate enough for now but I'll look at these methods to
try and get rid of the fudge factors. From reading SMPTE ST 2110 it seems
the RTP has to be a sample of the audio clock i.e. the SDP offset should be
0. That matches all the streams I've seen.

James



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: AES67 sender pipeline options

Sebastian Dröge-3
Hi James,

On Tue, 2019-01-29 at 19:38 -0600, James Cowdery wrote:
> I see the RTPs markers are the symptom not the cause of the discontinuities.
> I went back my code just before I added rtpbin and it doesn't have the
> regular 40ms discontinuities.

That seems unlikely to be the cause. rtpbin is not causing any changes
to the RTP packets (like setting the marker flag) and also wouldn't
cause timestamp differences. This is all happening before the rtpbin in
the payloader.

Are you sure you have the same properties on the payloader? The
"perfect-rtptime" property for example might be related to this.

> It also doesn't have the fast preroll and just starts immediately at
> 1 packet per ms.

What do you mean with this exactly?

> That code plays back OK with an 8ms fudge factor to get initial
> timestamp-offset right.

Where do these 8ms come from? That sounds like your code to set the
timestamp-offset is not correct yet. In theory you should get this
exactly correct based on the timestamp of the incoming buffer.

Your code to set the timestamp-offset should not do anything with the
clock itself, like measuring what time it is now.

> I'll need RTCP at some point but for now I've ditched it for now and work on
> getting that clean and robust.
>
> Thanks for advice on setting the payloader timestamp offset. The method I
> have working is accurate enough for now but I'll look at these methods to
> try and get rid of the fudge factors. From reading SMPTE ST 2110 it seems
> the RTP has to be a sample of the audio clock i.e. the SDP offset should be
> 0. That matches all the streams I've seen.

I wasn't aware of that constraints of ST2110, but for e.g. AES67 or
Ravenna this is not required (or RFC7273 in general) and non-0 media
clock offsets are allowed.

--
Sebastian Dröge, Centricular Ltd · https://www.centricular.com


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

signature.asc (981 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: AES67 sender pipeline options

James Cowdery
Sebastian,

From SMPTE 2110-30 which specifies how to use AES67 in broadcast
applications:

/Note 1: The media clock and the network timebase share the SMPTE ST 2059-1
epoch, with an offset of zero between
the Media Clock and the RTP Clock, as specified in SMPTE ST 2110-10.
Note 2: To maintain compatibility with other RTP implementations such as
AES67, implementers ought to be mindful of
the offset provisions in those RTP standards, and the possibility that the
RTP Clock could be offset from the Media Clock.
N/

I read that as transmitters should all use 0 but receivers should use the
offset if specified. Now the ST 2110 suite of standards are mostly
applicable to broadcast but to maximize compatibility for all applications
vaguely related to broadcast, e.g. consoles, pro monitors etc. it would be
safer to use 0 offset in transmitters.

Thanks for the other pointers. I'll try integrating rtpbin back and see what
caused the discontinuities. My code is still setting timestamp-offset before
the pipeline is set to run as setting it afterwards isn't effective so I
have to directly sample the PTP clock hence the fudge factor. 170ms just
seems a bit large.
Anyway I now have something that is hacked and ugly but works and can be
used as a reference. From here it will be easier to get things right. Would
adding a block after the payloader that owns the timestamps make sense from
an architectural standpoint? I need a structure that can react to PTP jumps
if they occur mid-stream.
James




--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: AES67 sender pipeline options

Sebastian Dröge-3
Hi James,

On Wed, 2019-01-30 at 11:45 -0600, James Cowdery wrote:

>
> From SMPTE 2110-30 which specifies how to use AES67 in broadcast
> applications:
>
> /Note 1: The media clock and the network timebase share the SMPTE ST 2059-1
> epoch, with an offset of zero between
> the Media Clock and the RTP Clock, as specified in SMPTE ST 2110-10.
> Note 2: To maintain compatibility with other RTP implementations such as
> AES67, implementers ought to be mindful of
> the offset provisions in those RTP standards, and the possibility that the
> RTP Clock could be offset from the Media Clock.
> N/
>
> I read that as transmitters should all use 0 but receivers should use the
> offset if specified. Now the ST 2110 suite of standards are mostly
> applicable to broadcast but to maximize compatibility for all applications
> vaguely related to broadcast, e.g. consoles, pro monitors etc. it would be
> safer to use 0 offset in transmitters.
Thanks, that's also how I would understand it. It is recommended for
receivers to handle non-0 offsets for compatibility reasons but
transmitters based on this standard alone should always use 0.

> Thanks for the other pointers. I'll try integrating rtpbin back and see what
> caused the discontinuities. My code is still setting timestamp-offset before
> the pipeline is set to run as setting it afterwards isn't effective so I
> have to directly sample the PTP clock hence the fudge factor. 170ms just
> seems a bit large.

Maybe you connected the RTP stream to the wrong pads of rtpbin? In your
case it should go to "send_rtp_sink_0" and will come out of
"send_rtp_src_0". If you had used the "recv_*" pads that would explain
the ~200ms delay.

For setting the "timestamp-offset" property, it's indeed a bit tricky
to set the correctly. The payloader will only make use of that property
once in the beginning when it receives the CAPS event from upstream.
But at that point you don't really know the buffer timestamp yet.

A solution would be to use a pad probe to intercept all serialized
events and store them, and then when the pad probe receives the first
buffer you can know based on its timestamps what to set the property
to... and before letting the buffer pass you would push through all the
events that you previously stored. It's a bit hackish but that should
work and give you 0ms instead of 8ms :)

> Anyway I now have something that is hacked and ugly but works and can be
> used as a reference. From here it will be easier to get things right. Would
> adding a block after the payloader that owns the timestamps make sense from
> an architectural standpoint? I need a structure that can react to PTP jumps
> if they occur mid-stream.

I think instead of fixing up timestamps afterwards you should rather
understand why there are discontinuities and solve the underlying
problem. It means that something is not working as expected further
upstream.

The RTP timestamps are solely based on the timestamps of the buffers
going into the payloader, so if those are wrong that's where you should
look (and fixing those timestamps would also be an option then).

You might want to put the audiobuffersplit element before the payloader
though. That will split buffers into equal-sized chunks as its main
job, but as a side-effect will also result in a perfectly timestamped
stream and will smooth out timestamp jitter (if that's the problem).

--
Sebastian Dröge, Centricular Ltd · https://www.centricular.com


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

signature.asc (981 bytes) Download Attachment