Last active
July 25, 2024 14:56
-
-
Save philhartung/72a2296a8c83a3468ffba509cdc9d104 to your computer and use it in GitHub Desktop.
Sync to PTPv2 clock and send RTP according to AES67. SAP/SDP not implemented here.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import gi | |
gi.require_version('Gst', '1.0') | |
gi.require_version('GstNet', '1.0') | |
from gi.repository import Gst, GstNet, GObject, GLib | |
Gst.init([]) | |
mainloop = GLib.MainLoop() | |
# audiotestsrc to aes67 | |
pipelineString = """ | |
audiotestsrc freq=480 volume=0.1 ! | |
audioconvert ! | |
audio/x-raw, format=S24BE, channels=2, rate=48000 ! | |
rtpL24pay name=rtppay min-ptime=1000000 max-ptime=1000000 ! | |
application/x-rtp, clock-rate=48000, channels=2, payload=98 ! | |
udpsink host=239.69.0.121 port=5004 qos=true qos-dscp=34 multicast-iface=eth0 | |
""" | |
if GstNet.ptp_init(GstNet.PTP_CLOCK_ID_NONE, ['eth0']): | |
print('PTP initialized') | |
else: | |
print('PTP failed to initialize') | |
sys.exit() | |
ptpClock = GstNet.PtpClock.new('PTP-Master', 0) | |
if ptpClock != None: | |
print('PTP clock obtained') | |
else: | |
print('PTP failed to obtain clock') | |
sys.exit() | |
def ptpstats(domain, stats, userdata): | |
t = stats.get_name() | |
if t == GstNet.PTP_STATISTICS_NEW_DOMAIN_FOUND: | |
print('PTP new domain found') | |
elif t == GstNet.PTP_STATISTICS_BEST_MASTER_CLOCK_SELECTED: | |
print("PTP master clock selected") | |
elif t == GstNet.PTP_STATISTICS_PATH_DELAY_MEASURED: | |
print('PTP path delay measured') | |
elif t == GstNet.PTP_STATISTICS_TIME_UPDATED: | |
print('PTP time updated') | |
if ptpClock.is_synced(): | |
calcOffset = (round((ptpClock.get_time()) * (48 / 1000000)) & 0xffffffff) | |
currentOffset = pipeline.get_by_name('rtppay').get_property("timestamp") | |
diff = (currentOffset - calcOffset) | |
print("Difference of", diff, "samples") | |
if diff < 0: | |
pipeline.set_state(Gst.State.PAUSED) | |
pipeline.set_state(Gst.State.READY) | |
calcOffset = (round((ptpClock.get_time()) * (48 / 1000000)) & 0xffffffff) - diff + 96 | |
pipeline.get_by_name('rtppay').set_property("timestamp-offset", calcOffset) | |
pipeline.set_state(Gst.State.PLAYING) | |
return True | |
GstNet.ptp_statistics_callback_add(ptpstats, None) | |
print('PTP Syncing to Master') | |
ptpClock.wait_for_sync(Gst.CLOCK_TIME_NONE) | |
print('PTP successfully synced to Master') | |
pipeline = Gst.parse_launch(pipelineString) | |
pipeline.use_clock(ptpClock) | |
# calculate intial offset (gstreamer uses random offset as default) | |
ptpOffset = (round((ptpClock.get_time()) * (48000 / 1000000000)) & 0xffffffff) # convert ptp nanosecond timestamp to mediaclock add 72 (1.5ms) as offset for time alignment | |
# ptpOffset = (round((ptpClock.get_time()) * (48000 / 1000000000)) & 0xffffffff) + round(20*48) # convert ptp nanosecond timestamp to mediaclock add 72 (1.5ms) as offset for time alignment | |
pipeline.get_by_name('rtppay').set_property("timestamp-offset", ptpOffset) | |
pipeline.set_state(Gst.State.PLAYING) | |
print('starting mainloop') | |
mainloop.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment