mediabus 0.3.2.1 → 0.3.3.0
raw patch · 5 files changed
+142/−161 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Data.MediaBus.Media.Reframe: InputFrameIsEarly :: PushFrameError
- Data.MediaBus.Media.Reframe: InputFrameIsLate :: PushFrameError
- Data.MediaBus.Media.Reframe: InputFrameOverlaps :: PushFrameError
- Data.MediaBus.Media.Reframe: MkReframeError :: String -> Maybe d -> ReframerSt s d -> ReframeError s d
- Data.MediaBus.Media.Reframe: data PushFrameError
- Data.MediaBus.Media.Reframe: data ReframeError s d
- Data.MediaBus.Media.Reframe: data ReframerSt s d
- Data.MediaBus.Media.Reframe: generateFrame :: (Num s, Num d, Monad m, Eq d, Ord d, Show d) => d -> ReframerT m s d (Frame s d d)
- Data.MediaBus.Media.Reframe: initialReframerState :: (Num d, Num s) => ReframerSt s d
- Data.MediaBus.Media.Reframe: instance (GHC.Show.Show s, Data.Typeable.Internal.Typeable * s, GHC.Show.Show d, Data.Typeable.Internal.Typeable * d) => GHC.Exception.Exception (Data.MediaBus.Media.Reframe.ReframeError s d)
- Data.MediaBus.Media.Reframe: instance (GHC.Show.Show s, GHC.Show.Show d) => GHC.Show.Show (Data.MediaBus.Media.Reframe.ReframeError s d)
- Data.MediaBus.Media.Reframe: instance (GHC.Show.Show s, GHC.Show.Show d) => GHC.Show.Show (Data.MediaBus.Media.Reframe.ReframerSt s d)
- Data.MediaBus.Media.Reframe: instance GHC.Classes.Eq Data.MediaBus.Media.Reframe.PushFrameError
- Data.MediaBus.Media.Reframe: instance GHC.Classes.Ord Data.MediaBus.Media.Reframe.PushFrameError
- Data.MediaBus.Media.Reframe: instance GHC.Enum.Enum Data.MediaBus.Media.Reframe.PushFrameError
- Data.MediaBus.Media.Reframe: instance GHC.Show.Show Data.MediaBus.Media.Reframe.PushFrameError
- Data.MediaBus.Media.Reframe: mkReFrameError :: Monad m => String -> Maybe d -> ReframerT m s d (ReframeError s d)
- Data.MediaBus.Media.Reframe: nextFrameAvailableDuration :: (Num d, Monad m) => ReframerT m s d d
- Data.MediaBus.Media.Reframe: nextFrameTimestamp :: (Num d, Monad m) => ReframerT m s d d
- Data.MediaBus.Media.Reframe: pushFrame :: (Num d, Monad m, Eq d, Ord d) => Frame s d d -> ReframerT m s d (Maybe PushFrameError)
- Data.MediaBus.Media.Reframe: pushStartFrame :: (Num d, Monad m) => d -> ReframerT m s d ()
- Data.MediaBus.Media.Reframe: runReframer :: Monad m => ReframerT m s d a -> ReframerSt s d -> m (a, ReframerSt s d)
- Data.MediaBus.Media.Reframe: type ReframerT m s d a = StateT (ReframerSt s d) m a
+ Data.MediaBus.Media.SyncStream: assumeSynchronized :: Stream i s t p c -> SyncStream i p c
+ Data.MediaBus.Media.SyncStream: setSequenceNumbersAndTimestamps :: (Num s, CanBeTicks r t, HasDuration c) => SyncStream i p c -> (s, Ticks r t) -> (Stream i s (Ticks r t) p c, (s, Ticks r t))
+ Data.MediaBus.Media.SyncStream: type SyncStream i p c = Stream i () () p c
- Data.MediaBus.Basics.Series: _Next :: forall a_aqe6 b_aqe7 b_aqs9. Prism (Series a_aqe6 b_aqs9) (Series a_aqe6 b_aqe7) b_aqs9 b_aqe7
+ Data.MediaBus.Basics.Series: _Next :: forall a_aqaM b_aqaN b_aqoP. Prism (Series a_aqaM b_aqoP) (Series a_aqaM b_aqaN) b_aqoP b_aqaN
- Data.MediaBus.Basics.Series: _Start :: forall a_aqe6 b_aqe7 a_aqse. Prism (Series a_aqse b_aqe7) (Series a_aqe6 b_aqe7) a_aqse a_aqe6
+ Data.MediaBus.Basics.Series: _Start :: forall a_aqaM b_aqaN a_aqoU. Prism (Series a_aqoU b_aqaN) (Series a_aqaM b_aqaN) a_aqoU a_aqaM
- Data.MediaBus.Media.Discontinous: _Got :: forall a_aEhh a_aEJz. Prism (Discontinous a_aEJz) (Discontinous a_aEhh) a_aEJz a_aEhh
+ Data.MediaBus.Media.Discontinous: _Got :: forall a_aEdX a_aEGe. Prism (Discontinous a_aEGe) (Discontinous a_aEdX) a_aEGe a_aEdX
- Data.MediaBus.Media.Discontinous: _Missing :: forall a_aEhh. Prism' (Discontinous a_aEhh) ()
+ Data.MediaBus.Media.Discontinous: _Missing :: forall a_aEdX. Prism' (Discontinous a_aEdX) ()
- Data.MediaBus.Media.Stream: frameCtxInit :: forall i_aTbr s_aTbs t_aTbt p_aTbu p_aTl4. Lens (FrameCtx i_aTbr s_aTbs t_aTbt p_aTbu) (FrameCtx i_aTbr s_aTbs t_aTbt p_aTl4) p_aTbu p_aTl4
+ Data.MediaBus.Media.Stream: frameCtxInit :: forall i_aT86 s_aT87 t_aT88 p_aT89 p_aThJ. Lens (FrameCtx i_aT86 s_aT87 t_aT88 p_aT89) (FrameCtx i_aT86 s_aT87 t_aT88 p_aThJ) p_aT89 p_aThJ
- Data.MediaBus.Media.Stream: frameCtxSeqNumRef :: forall i_aTbr s_aTbs t_aTbt p_aTbu s_aTl5. Lens (FrameCtx i_aTbr s_aTbs t_aTbt p_aTbu) (FrameCtx i_aTbr s_aTl5 t_aTbt p_aTbu) s_aTbs s_aTl5
+ Data.MediaBus.Media.Stream: frameCtxSeqNumRef :: forall i_aT86 s_aT87 t_aT88 p_aT89 s_aThK. Lens (FrameCtx i_aT86 s_aT87 t_aT88 p_aT89) (FrameCtx i_aT86 s_aThK t_aT88 p_aT89) s_aT87 s_aThK
- Data.MediaBus.Media.Stream: frameCtxSourceId :: forall i_aTbr s_aTbs t_aTbt p_aTbu i_aTl6. Lens (FrameCtx i_aTbr s_aTbs t_aTbt p_aTbu) (FrameCtx i_aTl6 s_aTbs t_aTbt p_aTbu) i_aTbr i_aTl6
+ Data.MediaBus.Media.Stream: frameCtxSourceId :: forall i_aT86 s_aT87 t_aT88 p_aT89 i_aThL. Lens (FrameCtx i_aT86 s_aT87 t_aT88 p_aT89) (FrameCtx i_aThL s_aT87 t_aT88 p_aT89) i_aT86 i_aThL
- Data.MediaBus.Media.Stream: frameCtxTimestampRef :: forall i_aTbr s_aTbs t_aTbt p_aTbu t_aTl7. Lens (FrameCtx i_aTbr s_aTbs t_aTbt p_aTbu) (FrameCtx i_aTbr s_aTbs t_aTl7 p_aTbu) t_aTbt t_aTl7
+ Data.MediaBus.Media.Stream: frameCtxTimestampRef :: forall i_aT86 s_aT87 t_aT88 p_aT89 t_aThM. Lens (FrameCtx i_aT86 s_aT87 t_aT88 p_aT89) (FrameCtx i_aT86 s_aT87 t_aThM p_aT89) t_aT88 t_aThM
- Data.MediaBus.Media.Stream: framePayload :: forall s_aTlJ t_aTlK c_aTlL c_aTCm. Lens (Frame s_aTlJ t_aTlK c_aTlL) (Frame s_aTlJ t_aTlK c_aTCm) c_aTlL c_aTCm
+ Data.MediaBus.Media.Stream: framePayload :: forall s_aTio t_aTip c_aTiq c_aTz1. Lens (Frame s_aTio t_aTip c_aTiq) (Frame s_aTio t_aTip c_aTz1) c_aTiq c_aTz1
- Data.MediaBus.Media.Stream: frameSeqNum :: forall s_aTlJ t_aTlK c_aTlL s_aTCn. Lens (Frame s_aTlJ t_aTlK c_aTlL) (Frame s_aTCn t_aTlK c_aTlL) s_aTlJ s_aTCn
+ Data.MediaBus.Media.Stream: frameSeqNum :: forall s_aTio t_aTip c_aTiq s_aTz2. Lens (Frame s_aTio t_aTip c_aTiq) (Frame s_aTz2 t_aTip c_aTiq) s_aTio s_aTz2
- Data.MediaBus.Media.Stream: frameTimestamp :: forall s_aTlJ t_aTlK c_aTlL t_aTCo. Lens (Frame s_aTlJ t_aTlK c_aTlL) (Frame s_aTlJ t_aTCo c_aTlL) t_aTlK t_aTCo
+ Data.MediaBus.Media.Stream: frameTimestamp :: forall s_aTio t_aTip c_aTiq t_aTz3. Lens (Frame s_aTio t_aTip c_aTiq) (Frame s_aTio t_aTz3 c_aTiq) t_aTip t_aTz3
- Data.MediaBus.Media.Stream: stream :: forall i_aTCU s_aTCV t_aTCW p_aTCX c_aTCY i_aU2k s_aU2l t_aU2m p_aU2n c_aU2o. Iso (Stream i_aTCU s_aTCV t_aTCW p_aTCX c_aTCY) (Stream i_aU2k s_aU2l t_aU2m p_aU2n c_aU2o) (Streamish i_aTCU s_aTCV t_aTCW p_aTCX c_aTCY) (Streamish i_aU2k s_aU2l t_aU2m p_aU2n c_aU2o)
+ Data.MediaBus.Media.Stream: stream :: forall i_aTzz s_aTzA t_aTzB p_aTzC c_aTzD i_aTYZ s_aTZ0 t_aTZ1 p_aTZ2 c_aTZ3. Iso (Stream i_aTzz s_aTzA t_aTzB p_aTzC c_aTzD) (Stream i_aTYZ s_aTZ0 t_aTZ1 p_aTZ2 c_aTZ3) (Streamish i_aTzz s_aTzA t_aTzB p_aTzC c_aTzD) (Streamish i_aTYZ s_aTZ0 t_aTZ1 p_aTZ2 c_aTZ3)
Files
- mediabus.cabal +3/−2
- specs/Data/MediaBus/Media/SyncStreamSpec.hs +94/−0
- src/Data/MediaBus.hs +1/−1
- src/Data/MediaBus/Media/Reframe.hs +0/−158
- src/Data/MediaBus/Media/SyncStream.hs +44/−0
mediabus.cabal view
@@ -1,5 +1,5 @@ name: mediabus-version: 0.3.2.1+version: 0.3.3.0 cabal-version: >=1.10 build-type: Simple license: BSD3@@ -52,10 +52,10 @@ Data.MediaBus.Media.Channels Data.MediaBus.Media.Discontinous Data.MediaBus.Media.Media- Data.MediaBus.Media.Reframe Data.MediaBus.Media.Samples Data.MediaBus.Media.Segment Data.MediaBus.Media.Stream+ Data.MediaBus.Media.SyncStream Data.MediaBus.Transport.Udp build-depends: QuickCheck <2.10,@@ -150,6 +150,7 @@ other-modules: Data.MediaBus.Conduit.Audio.Raw.ResampleSpec Data.MediaBus.Media.BufferSpec+ Data.MediaBus.Media.SyncStreamSpec Data.MediaBus.Conduit.SegmentSpec Data.MediaBus.Conduit.ReorderSpec Data.MediaBus.Conduit.StreamSpec
+ specs/Data/MediaBus/Media/SyncStreamSpec.hs view
@@ -0,0 +1,94 @@+module Data.MediaBus.Media.SyncStreamSpec+ ( spec+ ) where++import Control.Lens+import Control.Monad.State+import Data.Function+import Data.MediaBus+import Debug.Trace+import Test.Hspec+import Test.QuickCheck++newtype FakePayload = FP+ { fakeDuration :: Ticks64At8000+ } deriving (Eq, Show, Num, Arbitrary, Ord)++instance HasDuration FakePayload where+ getDuration = view (to fakeDuration . nominalDiffTime)++spec :: Spec+spec =+ describe "setSequenceNumbersAndTimestamps" $ do+ it "increases the sequence number by one (only) for each frame" $+ let prop :: (NonEmptyList (SyncStream () () FakePayload)) -> Bool+ prop (NonEmpty inStr) =+ let expectedLastSeqNum =+ let isNext (MkStream (Next _)) = True+ isNext _ = False+ in max 0 (fromIntegral (length (filter isNext inStr)) - 1)+ actualLastSeqNum =+ let outStr =+ let z :: (SeqNum16, Ticks64At8000)+ z = (0, 0)+ in evalState+ (mapM+ (state . setSequenceNumbersAndTimestamps)+ inStr)+ z+ in case last outStr of+ MkStream (Next f) -> f ^. seqNum+ MkStream (Start f) -> max 0 (f ^. seqNum - 1)+ in expectedLastSeqNum == actualLastSeqNum+ in property prop+ it "increases the sequence number monotonic" $+ let prop :: (NonEmptyList (SyncStream () () FakePayload)) -> Bool+ prop (NonEmpty inStr) =+ let seqNumDiffs =+ let outFrames =+ let isNext (MkStream (Next _)) = True+ isNext _ = False+ outStr =+ let z :: (SeqNum16, Ticks64At8000)+ z = (0, 0)+ in evalState+ (mapM+ (state . setSequenceNumbersAndTimestamps)+ inStr)+ z+ in filter isNext outStr+ in zipWith ((-) `on` (view seqNum)) (drop 1 outFrames) outFrames+ in all (== 1) seqNumDiffs+ in property prop+ it "increases the timestamps by the duration of each frame" $+ let prop :: (NonEmptyList (SyncStream () () FakePayload)) -> Bool+ prop (NonEmpty inStr) =+ let isNext (MkStream (Next _)) = True+ isNext _ = False+ outFrames :: [Stream () SeqNum16 Ticks64At8000 () FakePayload]+ outFrames =+ let outStr =+ let z :: (SeqNum16, Ticks64At8000)+ z = (0, MkTicks 0)+ in evalState+ (mapM+ (state . setSequenceNumbersAndTimestamps)+ inStr)+ z+ in filter isNext outStr+ timestamps = map (view timestamp) outFrames+ expectedTimestamps :: [Ticks64At8000]+ expectedTimestamps =+ let inFramesWithoutLast =+ (filter isNext inStr)+ inDurations =+ map (view (from nominalDiffTime) . getDuration)+ inFramesWithoutLast++ in scanl (+) 0 inDurations+ in if and (zipWith (==) timestamps expectedTimestamps)+ then True+ else traceShow ( timestamps+ , expectedTimestamps+ , outFrames) False+ in property prop
src/Data/MediaBus.hs view
@@ -36,8 +36,8 @@ import Data.MediaBus.Media.Channels as X import Data.MediaBus.Media.Discontinous as X import Data.MediaBus.Media.Media as X-import Data.MediaBus.Media.Reframe as X import Data.MediaBus.Media.Samples as X import Data.MediaBus.Media.Segment as X import Data.MediaBus.Media.Stream as X+import Data.MediaBus.Media.SyncStream as X import Data.MediaBus.Transport.Udp as X
− src/Data/MediaBus/Media/Reframe.hs
@@ -1,158 +0,0 @@--- | This module contains functions and types for reframing the sequence number--- and timestamps of 'Frame's.------ This means that this module will allow you to record a set of incoming--- frames using 'pushFrame'. Whenever you want to extract the timing and--- sequence number information of the next frame with a given duration,--- use 'generateFrame'.-module Data.MediaBus.Media.Reframe- ( initialReframerState- , runReframer- , pushStartFrame- , pushFrame- , PushFrameError(..)- , nextFrameAvailableDuration- , nextFrameTimestamp- , generateFrame- , type ReframerT- , ReframerSt()- , ReframeError(..)- , mkReFrameError- ) where--import Control.Exception-import Control.Monad-import Control.Monad.Trans.State.Strict as State-import Data.MediaBus.Media.Stream-import Data.Typeable---- | Create an empty initial state.-initialReframerState- :: (Num d, Num s)- => ReframerSt s d-initialReframerState = MkTimeFrame 0 0 0---- | Run state 'ReframerSt' state transformer.-runReframer- :: Monad m- => ReframerT m s d a -> ReframerSt s d -> m (a, ReframerSt s d)-runReframer = runStateT---- | Reset the current timing and sequence number, and start with the given--- start time.-pushStartFrame- :: (Num d, Monad m)- => d -> ReframerT m s d ()-pushStartFrame d = do- (MkTimeFrame _ s _) <- State.get- State.put (MkTimeFrame d s d)---- | Increase the available duration by the duration in the frame, iff the--- timestamp of the given frame matches exactly the timestamp after the end--- of the available period, otherwise do nothing with the state and return--- 'True'.-pushFrame- :: (Num d, Monad m, Eq d, Ord d)- => Frame s d d -> ReframerT m s d (Maybe PushFrameError)-pushFrame (MkFrame ts _ dur) = do- (MkTimeFrame startTs nextSeq endTs) <- State.get- let endTs' = ts + dur- when (ts == endTs) (State.put (MkTimeFrame startTs nextSeq endTs'))- return- (if | ts < endTs && endTs' < endTs -> Just InputFrameIsLate- | ts < endTs && endTs' >= endTs -> Just InputFrameOverlaps- | ts > endTs -> Just InputFrameIsEarly- | ts == endTs -> Nothing)---- | Specifies in what way 'pushFrame' failed-data PushFrameError- = InputFrameIsLate -- ^ The input frame ends before '_endTs'- | InputFrameOverlaps -- ^ The input frame starts before, and ends after '_endTs'- | InputFrameIsEarly -- ^ The input frame begins after '_endTs'- deriving (Eq, Ord, Show, Enum)---- | Return the duration of the frames recorded with 'pushFrame'.-nextFrameAvailableDuration- :: (Num d, Monad m)- => ReframerT m s d d-nextFrameAvailableDuration = do- (MkTimeFrame startTs _ endTs) <- State.get- return (endTs - startTs)---- | Return the timestamp of the frame being build. .-nextFrameTimestamp- :: (Num d, Monad m)- => ReframerT m s d d-nextFrameTimestamp = do- (MkTimeFrame startTs _ _) <- State.get- return startTs---- | Try to create a frame with the given duration, and update the state--- accordingly, the actual duration, that was available is--- put into the payload field of the frame returned.--- The start time stamp of the next frame--- is always incremented by the @wantedDureation@ regardless of wether it was--- available.-generateFrame- :: (Num s, Num d, Monad m, Eq d, Ord d, Show d)- => d -> ReframerT m s d (Frame s d d)-generateFrame wantedDuration = do- (MkTimeFrame startTs nextSeq endTs) <- State.get- available <- nextFrameAvailableDuration- let endTs' = max (startTs + wantedDuration) endTs- State.put (MkTimeFrame (startTs + wantedDuration) (nextSeq + 1) endTs')- return (MkFrame startTs nextSeq (wantedDuration `min` available))---- | Reframer state.-data ReframerSt s d = MkTimeFrame- { _startTs :: !d- , _nextSeqNum :: !s- , _endTs :: !d- } deriving (Typeable)--instance (Show s, Show d) =>- Show (ReframerSt s d) where- showsPrec d MkTimeFrame {_startTs, _nextSeqNum, _endTs} =- showParen- (d > 10)- (showString "reframer-state: " .- showString "start: " .- showsPrec 11 _startTs .- showString ", end: " .- showsPrec 11 _endTs . showString ", next-sn: " . showsPrec 11 _nextSeqNum)---- | The 'ReframerSt' 'StateT' transformer-type ReframerT m s d a = StateT (ReframerSt s d) m a---- | The exception type for 'encodeLinearToAacC'-data ReframeError s d = MkReframeError- { reframeError :: String- , reframeErrorRequestedOutput :: Maybe d- , reframeErrorSt :: ReframerSt s d- } deriving (Typeable)--instance (Show s, Show d) =>- Show (ReframeError s d) where- showsPrec d MkReframeError { reframeError- , reframeErrorRequestedOutput- , reframeErrorSt- } =- showParen- (d > 10)- (showString "reframe-error: " .- showsPrec 11 reframeError .- maybe- id- (\ro -> showString ", requested: " . showsPrec 11 ro)- reframeErrorRequestedOutput .- showString ", " . showsPrec 11 reframeErrorSt)--instance (Show s, Typeable s, Show d, Typeable d) =>- Exception (ReframeError s d)---- | Utility function to generate a 'ReframeError' with the current state.-mkReFrameError- :: Monad m- => String -> Maybe d -> ReframerT m s d (ReframeError s d)-mkReFrameError msg requestedOutputDuration =- MkReframeError msg requestedOutputDuration <$> State.get
+ src/Data/MediaBus/Media/SyncStream.hs view
@@ -0,0 +1,44 @@+-- | Naturally ordered 'Stream's.+-- A 'Stream' without sequence numbers and timestamps has no means to represent+-- 'Frame's that have varying sequence numbers or timestamps, hence they cannot+-- be part of a stream that is not perfectly synchronized, therefore when consuming+-- such 'Stream' values, the corresponding callers must work under the assumption+-- that the frames are perfectly synchronous.+module Data.MediaBus.Media.SyncStream+ ( type SyncStream+ , assumeSynchronized+ , setSequenceNumbersAndTimestamps+ ) where++import Data.MediaBus.Basics.Series+import Data.MediaBus.Basics.Ticks+import Data.MediaBus.Media.Stream++-- | A 'Stream' without a meaningful sequence number or timestamp.+type SyncStream i p c = Stream i () () p c++-- | Convert a 'Stream' to a 'SyncStream' by simply /forgetting/ the sequence+-- numbers and timestamps of the input. This expresses the assumption that the+-- 'Frame's are either perfectly lined sequential or that this doesn't matter+-- at all.+assumeSynchronized :: Stream i s t p c -> SyncStream i p c+assumeSynchronized (MkStream (Start (MkFrameCtx i _ _ p))) =+ MkStream (Start (MkFrameCtx i () () p))+assumeSynchronized (MkStream (Next (MkFrame _ _ c))) =+ MkStream (Next (MkFrame () () c))++-- | Set sequence numbers and timestamps.+-- Increment the sequence numbers starting from @0@ for every frame.+-- Start the timestamp at @0@ and add the 'Frame' duration of the 'Next'+-- frame in the stream.+-- This function has the signature required to turn it into a 'State' monad.+setSequenceNumbersAndTimestamps+ :: (Num s, CanBeTicks r t, HasDuration c)+ => SyncStream i p c+ -> (s, Ticks r t)+ -> (Stream i s (Ticks r t) p c, (s, Ticks r t))+setSequenceNumbersAndTimestamps (MkStream (Next (MkFrame _t _s !c))) (nextS, nextT) =+ ( MkStream (Next (MkFrame nextT nextS c))+ , (nextS + 1, nextT + getDurationTicks c))+setSequenceNumbersAndTimestamps (MkStream (Start (MkFrameCtx i _t _s p))) (nextS, nextT) =+ ((MkStream (Start (MkFrameCtx i nextT nextS p))), (nextS, nextT))