@@ -55,16 +55,35 @@ final public class sACNSource {
5555
5656 /// Whether this source should actively output sACN Universe Discovery and Data messages.
5757 /// This may be useful for backup scenarios to ensure the source is ready to output as soon as required.
58- ///
59- /// Calling this before `startOutput()` will have no effect.
6058 public var shouldOutput : Bool {
6159 get { socketDelegateQueue. sync { _shouldOutput } }
62- set { socketDelegateQueue. sync { _shouldOutput = newValue } }
6360 }
6461
6562 /// The private state of should output.
6663 private var _shouldOutput : Bool
6764
65+ /// Updates whether this source source should actively output sACN Universe Discovery and Data messages.
66+ ///
67+ /// This may be useful for backup scenarios to ensure the source is ready to output as soon as required.
68+ ///
69+ /// Calling this before `startOutput()` will have no effect.
70+ ///
71+ /// - Parameters:
72+ /// - output: Whether the source should output.
73+ ///
74+ public func shouldOutput( _ output: Bool ) {
75+ socketDelegateQueue. sync {
76+ guard _shouldOutput != output else { return }
77+ if output {
78+ universes. forEach { $0. reset ( ) }
79+ } else {
80+ // terminate all universes on all sockets, but keep the sockets and universes present
81+ universes. forEach { $0. terminate ( remove: false ) }
82+ }
83+ _shouldOutput = output
84+ }
85+ }
86+
6887 // MARK: Delegate
6988
7089 /// Changes the source delegate of this source to the the object passed.
@@ -303,13 +322,18 @@ final public class sACNSource {
303322 if existingInterfaces. isEmpty {
304323 // not possible for IPv6
305324
306- // terminate all universes on existing sockets, removing the sockets but not the universes
307- let socketIds = sockets. reduce ( into: [ String: Bool] ( ) ) { dict, socket in
308- dict [ socket. key] = true
309- }
310- socketsShouldTerminate = socketIds
311- universes. forEach { universe in
312- universe. terminateSockets ( )
325+ if universes. isEmpty || !_isListening {
326+ // deinit first stops listening
327+ sockets. removeAll ( )
328+ } else {
329+ // terminate all universes on existing sockets, removing the sockets but not the universes
330+ let socketIds = sockets. reduce ( into: [ String: Bool] ( ) ) { dict, socket in
331+ dict [ socket. key] = true
332+ }
333+ socketsShouldTerminate = socketIds
334+ universes. forEach { universe in
335+ universe. terminateSockets ( )
336+ }
313337 }
314338
315339 // add each new interfaces
@@ -326,13 +350,18 @@ final public class sACNSource {
326350 } else if newInterfaces. isEmpty {
327351 // not possible for IPv6
328352
329- // terminate all universes on existing sockets, removing the sockets but not the universes
330- let socketIds = sockets. reduce ( into: [ String: Bool] ( ) ) { dict, socket in
331- dict [ socket. key] = true
332- }
333- socketsShouldTerminate = socketIds
334- universes. forEach { universe in
335- universe. terminateSockets ( )
353+ if universes. isEmpty || !_isListening {
354+ // deinit first stops listening
355+ sockets. removeAll ( )
356+ } else {
357+ // terminate all universes on existing sockets, removing the sockets but not the universes
358+ let socketIds = sockets. reduce ( into: [ String: Bool] ( ) ) { dict, socket in
359+ dict [ socket. key] = true
360+ }
361+ socketsShouldTerminate = socketIds
362+ universes. forEach { universe in
363+ universe. terminateSockets ( )
364+ }
336365 }
337366
338367 // add socket for all interfaces
@@ -351,12 +380,19 @@ final public class sACNSource {
351380 // terminate all universes on sockets no longer needed, removing the sockets but not the universes
352381 let socketsToRemove = sockets. filter { interfacesToRemove. contains ( $0. key) }
353382 if !socketsToRemove. isEmpty {
354- let socketIds = socketsToRemove. reduce ( into: [ String: Bool] ( ) ) { dict, socket in
355- dict [ socket. key] = true
356- }
357- socketsShouldTerminate = socketIds
358- universes. forEach { universe in
359- universe. terminateSockets ( )
383+ if universes. isEmpty || !_isListening {
384+ for socketToRemove in socketsToRemove. keys {
385+ // deinit first stops listening
386+ sockets. removeValue ( forKey: socketToRemove)
387+ }
388+ } else {
389+ let socketIds = socketsToRemove. reduce ( into: [ String: Bool] ( ) ) { dict, socket in
390+ dict [ socket. key] = true
391+ }
392+ socketsShouldTerminate = socketIds
393+ universes. forEach { universe in
394+ universe. terminateSockets ( )
395+ }
360396 }
361397 }
362398
@@ -756,8 +792,6 @@ private extension sACNSource {
756792
757793 /// Sends the data messages for this source.
758794 private func sendDataMessages( ) {
759- guard _shouldOutput else { return }
760-
761795 // remove all universes which are full terminated and should be removed
762796 let universesToRemove = universes. filter { $0. removeAfterTerminate && $0. shouldTerminate && $0. dirtyCounter < 1 }
763797 let universesReadyForSocketRemoval = universes. filter { $0. pendingSocketRemoval && $0. dirtyCounter < 1 }
@@ -848,7 +882,6 @@ private extension sACNSource {
848882 let dmpLayer = universe. dmpLevelsLayer
849883
850884 let levels = rootLayer+ framingLayer+ dmpLayer
851- universeMessages. append ( ( universeNumber: universe. number, data: levels) )
852885
853886 if !socketsShouldTerminate. isEmpty {
854887 let framingOptions : DataFramingLayer . Options = [ . terminated]
@@ -859,7 +892,10 @@ private extension sACNSource {
859892 socketTerminationMessages. append ( ( universeNumber: universe. number, data: levels) )
860893 }
861894
862- universe. incrementSequence ( )
895+ if _shouldOutput || ( universe. shouldTerminate && universe. dirtyCounter > 0 ) {
896+ universeMessages. append ( ( universeNumber: universe. number, data: levels) )
897+ universe. incrementSequence ( )
898+ }
863899 universe. decrementDirty ( )
864900 }
865901
@@ -871,17 +907,20 @@ private extension sACNSource {
871907 let dmpLayer = universe. dmpPrioritiesLayer
872908
873909 let priorities = rootLayer+ framingLayer+ dmpLayer
874- universeMessages. append ( ( universeNumber: universe. number, data: priorities) )
875910
876- universe. incrementSequence ( )
877- universe. prioritySent ( )
911+ if _shouldOutput || ( universe. shouldTerminate && universe. dirtyCounter > 0 ) {
912+ universeMessages. append ( ( universeNumber: universe. number, data: priorities) )
913+ universe. incrementSequence ( )
914+ universe. prioritySent ( )
915+ }
878916 }
879917
880918 universe. incrementCounter ( )
881919 }
882920
883921 sockets. forEach { interface, socket in
884922 let messages = socketsShouldTerminate [ interface] != nil ? socketTerminationMessages : universeMessages
923+
885924 for universeMessage in messages {
886925 if ipMode. usesIPv4 ( ) {
887926 let hostname = IPv4 . multicastHostname ( for: universeMessage. universeNumber)
0 commit comments