5454 * first-in first-out way from the streaming threads to the application.
5555 * <p>
5656 * See upstream documentation at
57- * <a href="https://gstreamer.freedesktop.org/data/doc/ gstreamer/stable/gstreamer/html/GstBus .html"
58- * >https://gstreamer.freedesktop.org/data/doc/ gstreamer/stable/gstreamer/html/GstBus .html</a>
57+ * <a href="https://gstreamer.freedesktop.org/documentation/ gstreamer/gstbus .html"
58+ * >https://gstreamer.freedesktop.org/documentation/ gstreamer/gstbus .html</a>
5959 * <p>
6060 * Since the application typically only wants to deal with delivery of these
6161 * messages from one thread, the Bus will marshal the messages between different
@@ -80,10 +80,11 @@ public class Bus extends GstObject {
8080 private static final Logger LOG = Logger .getLogger (Bus .class .getName ());
8181 private static final SyncCallback SYNC_CALLBACK = new SyncCallback ();
8282
83+ private volatile BusSyncHandler syncHandler = null ;
84+
8385 private final Object lock = new Object ();
8486 private final List <MessageProxy <?>> messageProxies = new CopyOnWriteArrayList <>();
8587 private boolean watchAdded = false ;
86- private BusSyncHandler syncHandler = null ;
8788
8889 /**
8990 * This constructor is used internally by gstreamer-java
@@ -468,14 +469,46 @@ public boolean post(Message message) {
468469 return GSTBUS_API .gst_bus_post (this , message );
469470 }
470471
471- public BusSyncHandler getSyncHandler () {
472- return syncHandler ;
473- }
474-
472+ /**
473+ * Sets the synchronous handler (message listener) on the bus. The handler
474+ * will be called every time a new message is posted on the bus. Note that
475+ * the handler will be called in the same thread context as the posting
476+ * object. Applications should generally handle messages asynchronously
477+ * using the other message listeners.
478+ * <p>
479+ * Only one handler may be attached to the bus at any one time. An attached
480+ * sync handler forces creation of {@link Message} objects for all messages
481+ * on the bus, so the handler should be removed if no longer required.
482+ * <p>
483+ * A single native sync handler is used at all times, with synchronous and
484+ * asynchronous dispatch handled on the Java side, so the bindings do not
485+ * inherit issues in clearing or replacing the sync handler with versions of
486+ * GStreamer prior to 1.16.3.
487+ *
488+ * @param handler bus sync handler, or null to remove
489+ */
475490 public void setSyncHandler (BusSyncHandler handler ) {
476491 syncHandler = handler ;
477492 }
478493
494+ /**
495+ * Clear the synchronous handler.
496+ * <p>
497+ * This is a convenience method equivalent to {@code setSyncHandler(null)}
498+ */
499+ public void clearSyncHandler () {
500+ setSyncHandler (null );
501+ }
502+
503+ /**
504+ * Get the current synchronous handler.
505+ *
506+ * @return current sync handler, or null
507+ */
508+ public BusSyncHandler getSyncHandler () {
509+ return syncHandler ;
510+ }
511+
479512 /**
480513 * Connects to a signal.
481514 *
@@ -880,9 +913,11 @@ private static class SyncCallback implements GstBusAPI.BusSyncHandler {
880913 @ Override
881914 public BusSyncReply callback (final GstBusPtr busPtr , final GstMessagePtr msgPtr , Pointer userData ) {
882915 Bus bus = Natives .objectFor (busPtr , Bus .class , true , true );
883- if (bus .syncHandler != null ) {
916+ // volatile - use local reference
917+ BusSyncHandler syncHandler = bus .syncHandler ;
918+ if (syncHandler != null ) {
884919 Message msg = Natives .objectFor (msgPtr , Message .class , true , true );
885- BusSyncReply reply = bus . syncHandler .syncMessage (msg );
920+ BusSyncReply reply = syncHandler .syncMessage (msg );
886921 if (reply != BusSyncReply .DROP ) {
887922 Gst .getExecutor ().execute (() -> bus .dispatchMessage (busPtr , msgPtr ));
888923 } else {
0 commit comments