module Data.MediaBus.Transport.Udp ( udpDatagramSource ) where import Control.Lens import Control.Monad.State.Strict import Control.Monad.Trans.Resource import Conduit import Data.Conduit.Network.UDP import Data.MediaBus.Basics.Clock import Data.MediaBus.Conduit.Stream import Data.MediaBus.Media.Stream import Data.MediaBus.Basics.SourceId import Data.MediaBus.Basics.Sequence import Data.Streaming.Network import Network.Socket ( SockAddr, close ) import qualified Data.ByteString as B import Data.Default -- | A UDP source that uses 'MonandResource' to make sure the socket is closed. udpDatagramSource :: (IsClock c, MonadClock c m, MonadResource m, Num s, Default p) => proxy c -> Int -> HostPreference -> Source m (Stream (SourceId (Maybe SockAddr)) (SeqNum s) (ClockTimeDiff c) p B.ByteString) udpDatagramSource _clk port host = do !t0 <- lift now bracketP (bindPortUDP port host) close (`sourceSocket` 1024) .| evalStateC (Nothing, 0, t0) (awaitForever createFrame) where createFrame m = do let currentSender = msgSender m lastSender <- _1 <<.= Just currentSender tNow <- lift (lift now) when (Just currentSender /= lastSender) $ do _2 .= 0 _3 .= tNow yieldStartFrameCtx (MkFrameCtx (MkSourceId (Just currentSender)) (timeAsTimeDiff tNow) 0 def) sn <- _2 <<+= 1 tStart <- use _3 yieldNextFrame (MkFrame (diffTime tNow tStart) sn (msgData m))