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 |
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 |
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 |
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? 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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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. 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 |
Free forum by Nabble | Edit this page |