diff --git a/bench/Encoder.hs b/bench/Encoder.hs
--- a/bench/Encoder.hs
+++ b/bench/Encoder.hs
@@ -2,54 +2,69 @@
   ( main
   ) where
 
-import Control.Monad
 import Control.Monad.Logger
+import Criterion.Main
 import Data.Conduit
+import Data.Conduit.List
 import Data.MediaBus
 import Data.MediaBus.FdkAac
-import Data.Conduit.List
 import Data.Time.Clock
 import Data.Typeable
-import Criterion.Main
-import Control.Lens
-import Data.Vector.Storable as V
 import Data.Word
 import GHC.TypeLits
 
 main :: IO ()
-main =
-  defaultMain
-    [bgroupFromTestDuration 1000 16000, bgroupFromTestDuration 1000 48000]
+main = defaultMain [bgroupFromTestDuration 1]
 
-bgroupFromTestDuration :: NominalDiffTime -> Int -> Benchmark
-bgroupFromTestDuration testdur samplesPerSecond =
-  bgroup
-    (show testdur Prelude.++ " ptime=20ms " Prelude.++ show samplesPerSecond Prelude.++
-     " Hz") $
+bgroupFromTestDuration :: NominalDiffTime -> Benchmark
+bgroupFromTestDuration testdur =
+  bgroup (show testdur Prelude.++ " ptime=20ms") $
   let frameCount = ceiling (testdur / ptime)
       ptime = 20 / 1000
   in [ bgroup
-         "AAC HE"
+         "AAC HE 16kHz"
          [ bench "Stereo" $
            nfIO $
            encodeNFrames (aacEncoderConfig aacHe16KhzStereo) $
-           testFrames testdur frameCount
+           testFrames ptime frameCount
          , bench "Mono" $
            nfIO $
            encodeNFrames (aacEncoderConfig aacHe16KhzMono) $
-           testFrames testdur frameCount
+           testFrames ptime frameCount
          ]
      , bgroup
-         "AAC LC"
+         "AAC LC 16kHz"
          [ bench "Stereo" $
            nfIO $
            encodeNFrames (aacEncoderConfig aacLc16KhzStereo) $
-           testFrames testdur frameCount
+           testFrames ptime frameCount
          , bench "Mono" $
            nfIO $
            encodeNFrames (aacEncoderConfig aacLc16KhzMono) $
-           testFrames testdur frameCount
+           testFrames ptime frameCount
          ]
+     , bgroup
+         "AAC HE 48kHz"
+         [ bench "Stereo" $
+           nfIO $
+           encodeNFrames (aacEncoderConfig aacHe48KhzStereo) $
+           testFrames ptime frameCount
+         , bench "Mono" $
+           nfIO $
+           encodeNFrames (aacEncoderConfig aacHe48KhzMono) $
+           testFrames ptime frameCount
+         ]
+     , bgroup
+         "AAC LC 48kHz"
+         [ bench "Stereo" $
+           nfIO $
+           encodeNFrames (aacEncoderConfig aacLc48KhzStereo) $
+           testFrames ptime frameCount
+         , bench "Mono" $
+           nfIO $
+           encodeNFrames (aacEncoderConfig aacLc48KhzMono) $
+           testFrames ptime frameCount
+         ]
      ]
 
 encodeNFrames
@@ -64,23 +79,19 @@
      , Typeable r
      )
   => AacEncoderConfig r channels aot
-  -> [Stream SrcId32 SeqNum16 (Ticks r Word64) () (Audio r channels (Raw S16))]
-  -> IO [Stream SrcId32 SeqNum16 (Ticks r Word64) (AacEncoderInfo r channels aot) (Audio r channels (Aac aot))]
+  -> [SyncStream SrcId32 () (Audio r channels (Raw S16))]
+  -> IO [Stream SrcId32 SeqNum64 (Ticks r Word64) (AacEncoderInfo r channels aot) (Audio r channels (Aac aot))]
 encodeNFrames cfg pcms =
   runStdoutLoggingT $
-  runConduitRes $ sourceList pcms .| encodeLinearToAacC cfg .| consume
+  runConduitRes $
+  sourceList pcms .| encodeLinearToAacC cfg .| setSequenceNumberAndTimestampC .|
+  consume
 
 testFrames
   :: (KnownRate r, IsPcmValue (Pcm channels S16))
   => NominalDiffTime
   -> Int
-  -> [Stream SrcId32 SeqNum16 (Ticks r Word64) () (Audio r channels (Raw S16))]
+  -> [SyncStream SrcId32 () (Audio r channels (Raw S16))]
 testFrames frameDuration frames =
-  [ MkStream
-    (Next
-       (MkFrame
-          (fromIntegral x * (nominalDiffTime # frameDuration))
-          (fromIntegral x)
-          (blankFor frameDuration)))
-  | x <- [0 .. frames]
-  ]
+  Prelude.replicate frames $
+  MkStream (Next (MkFrame () () (blankFor frameDuration)))
diff --git a/examples/Main.hs b/examples/Main.hs
--- a/examples/Main.hs
+++ b/examples/Main.hs
@@ -13,15 +13,16 @@
 
 encodeOneSeconfOfSilence
   :: IO [Stream SrcId32
-                SeqNum16
+                SeqNum64
                 (Ticks64 (Hz 48000))
                 (AacEncoderInfo (Hz 48000) Stereo 'HighEfficiency)
                 (Audio (Hz 48000) Stereo (Aac 'HighEfficiency))]
 encodeOneSeconfOfSilence =
   runStdoutLoggingT $
   runConduitRes $
-        yieldNextFrame (MkFrame 0 0 pcmAudioOneSecond)
+        yieldNextFrame (MkFrame () () pcmAudioOneSecond)
      .| encodeLinearToAacC encoderConfig
+     .| setSequenceNumberAndTimestampC
      .| traceShowSink 1 "Example Trace"
 
   where
diff --git a/mediabus-fdk-aac.cabal b/mediabus-fdk-aac.cabal
--- a/mediabus-fdk-aac.cabal
+++ b/mediabus-fdk-aac.cabal
@@ -1,5 +1,5 @@
 name: mediabus-fdk-aac
-version: 0.3.2.1
+version: 0.4.0.0
 cabal-version: >=1.10
 build-type: Simple
 license: BSD3
@@ -27,7 +27,7 @@
         deepseq <1.5,
         inline-c <0.6,
         lens <4.16,
-        mediabus <0.4,
+        mediabus ==0.4.*,
         monad-logger <0.4,
         random <1.2,
         resourcet <1.2,
@@ -67,8 +67,8 @@
         ghc-prim <0.6,
         lens <4.16,
         monad-logger <0.4,
-        mediabus-fdk-aac <0.4,
-        mediabus <0.4,
+        mediabus-fdk-aac <0.5,
+        mediabus ==0.4.*,
         conduit <1.3,
         vector <13
     default-language: Haskell2010
@@ -93,9 +93,10 @@
         ghc-prim <0.6,
         lens <4.16,
         monad-logger <0.4,
+        time <1.7,
         criterion <1.2,
-        mediabus-fdk-aac <0.4,
-        mediabus <0.4,
+        mediabus-fdk-aac <0.5,
+        mediabus ==0.4.*,
         conduit <1.3,
         vector <13
     default-language: Haskell2010
diff --git a/src/Data/MediaBus/FdkAac/Conduit/Encoder.hs b/src/Data/MediaBus/FdkAac/Conduit/Encoder.hs
--- a/src/Data/MediaBus/FdkAac/Conduit/Encoder.hs
+++ b/src/Data/MediaBus/FdkAac/Conduit/Encoder.hs
@@ -6,25 +6,26 @@
   ) where
 
 import Conduit
-import Control.Lens
-import Control.Monad
 import Control.Monad.Logger
-import Control.Monad.Trans.State.Strict as State
 import Data.MediaBus
 import Data.MediaBus.FdkAac.Encoder
-import Data.String
 import Data.Tagged
 import Data.Typeable
 import GHC.TypeLits
 
-
 --  * Conduit Based 'Stream' Encoding
 -- | A conduit that receives signed 16 bit, mono or stereo, 'Raw' 'Audio' and
--- yields AAC encoded frames. The timestamps of the input frames will be
--- regarded such that gaps in the timestamps are reflected in the generated
--- frames. The sequence numbering will be
+-- yields AAC encoded frames.
+-- When a 'Start' event is received, the delay lines will be flushed.
+-- The timestamps and sequence numbers of the input will be ignored.
+-- The output sequence numbers start from zero and increase
+-- monotonic. 'Start' events don't lead to resetting neither sequence numbers
+-- nor timestamps.
+-- The timestamps start at the encoder delay and are increased by 'frameSize'
+-- and the type signature requires that the timestamp unit for 'Frame's has the
+-- same sampling rate as the encoded audio.
 encodeLinearToAacC
-  :: forall channels r aot i s t m.
+  :: forall channels r aot i m.
      ( MonadLoggerIO m
      , MonadThrow m
      , MonadResource m
@@ -34,81 +35,24 @@
      , Show (AacAotProxy aot)
      , KnownNat (GetAacAot aot)
      , Show i
-     , Show t
-     , Typeable t
-     , LocalOrd t
-     , Show s
-     , Typeable s
-     , Num t
-     , Num s
      , CanBeSample (Pcm channels S16)
      , Show (Pcm channels S16)
-     , Integral t
      )
   => AacEncoderConfig r channels aot
-  -> Conduit (Stream i s (Ticks r t) () (Audio r channels (Raw S16))) m (Stream i s (Ticks r t) (AacEncoderInfo r channels aot) (Audio r channels (Aac aot)))
+  -> Conduit (SyncStream i () (Audio r channels (Raw S16))) m (SyncStream i (AacEncoderInfo r channels aot) (Audio r channels (Aac aot)))
 encodeLinearToAacC aacCfg = do
   (Tagged enc, info) <- lift $ aacEncoderAllocate aacCfg
-  (_res, _st, ()) <-
-    prefixLogsC (show enc ++ " - ") $
-    runRWSC
-      enc
-      (MkAacEncSt @r @channels @aot 0)
-      (evalStateC
-         (initialReframerState :: ReframerSt s (Ticks r t))
-         (encodeThenFlush info))
-  return ()
+  prefixLogsC (show enc ++ " - ") $ runReaderC enc (encodeThenFlush info)
   where
     encodeThenFlush info = do
       awaitForever go
-      aacs <- lift $ lift flushAacEncoder
-      Prelude.mapM_ yieldAacFrame aacs
+      aacs <- lift flushAacEncoder
+      Prelude.mapM_ yieldNextFrame aacs
       where
         go (MkStream (Next f)) = do
-          let reframeFrame = f & framePayload %~ getDurationTicks
-          $logDebug (fromString ("in: " ++ show f))
-          pushRes <- lift $ pushFrame reframeFrame
-          case pushRes of
-            Nothing -> return ()
-            Just er -> do
-              $logInfo
-                (fromString
-                   ("frame timing problem: " ++ show er ++ ", frame: " ++
-                    show reframeFrame))
-              lift $ State.get >>= $logInfoSH
-              aacs <- lift $ lift flushAacEncoder
-              Prelude.mapM_ yieldAacFrame aacs
-              lift $
-                pushStartFrame
-                  (reframeFrame ^. frameTimestamp + reframeFrame ^. framePayload)
-          aacs <-
-            lift $ lift $
-            encodeLinearToAac (view framePayload f)
-          Prelude.mapM_ yieldAacFrame aacs
-        go start@(MkStream (Start (MkFrameCtx fi ft fs _fp))) = do
-          lift $ pushStartFrame ft
-          lift $ $logDebug (fromString ("in: " ++ show start))
-          let outStart = MkFrameCtx fi ft fs info
-          lift $ $logDebug (fromString ("out: " ++ show outStart))
+          aacs <- lift (encodeLinearToAac f)
+          Prelude.mapM_ yieldNextFrame aacs
+        go (MkStream (Start (MkFrameCtx fi _ _ _))) = do
+          lift flushAacEncoder >>= Prelude.mapM_ yieldNextFrame
+          let outStart = MkFrameCtx fi () () info
           yieldStartFrameCtx outStart
-        yieldAacFrame fc =
-          let wantDur = getDurationTicks fc
-          in when (wantDur > 0) $ do
-               frm <- lift $ generateFrame wantDur
-               when (frm ^. framePayload < wantDur) $ do
-                 $logInfo
-                   (fromString
-                      ("encoder generated more output than input, input: " ++
-                       show (frm ^. framePayload) ++
-                       " < output: " ++
-                       show wantDur))
-                 availDur <- lift nextFrameAvailableDuration
-                 $logInfo
-                   (fromString
-                      ("samples enqueuend in the encoder delay lines: " ++
-                       show availDur))
-                 rfst <- lift $ State.get
-                 $logInfoSH rfst
-               let outFrm = frm & framePayload .~ fc
-               $logDebug (fromString ("out: " ++ show outFrm))
-               yieldNextFrame outFrm
diff --git a/src/Data/MediaBus/FdkAac/Encoder.hs b/src/Data/MediaBus/FdkAac/Encoder.hs
--- a/src/Data/MediaBus/FdkAac/Encoder.hs
+++ b/src/Data/MediaBus/FdkAac/Encoder.hs
@@ -5,7 +5,7 @@
 --   For an easy to use, high-level interface please consult
 --   'Data.MediaBus.FdkAac.Conduit.Encoder'.
 module Data.MediaBus.FdkAac.Encoder
-  ( aacFrameSize
+  ( aacFrameDuration
   , aacFrameMediaData
   , Aac
   , aacHe48KhzStereo
@@ -29,8 +29,6 @@
   , type GetAacAot
   , aacEncoderAllocate
   , type AacEncT
-  , AacEncSt(..)
-  , numberOfDelayedSamples
   , encodeLinearToAac
   , flushAacEncoder
   ) where
@@ -39,10 +37,9 @@
 import Control.DeepSeq
 import Control.Lens
 import Control.Monad.Logger
-import Control.Monad.Trans.RWS.Strict
+import Control.Monad.Trans.Reader
 import Control.Monad.Trans.Resource
 import Data.Kind
-import Data.Maybe
 import Data.MediaBus
 import Data.MediaBus.FdkAac.EncoderFdkWrapper
 import Data.Proxy
@@ -58,9 +55,9 @@
 -- | This is the media type for AAC encoded audio data.
 data Aac (aot :: AacAot)
 
-data instance  Audio r c (Aac aot) = MkAacFrame{aacFrameMediaData
-                                                :: !(V.Vector Word8),
-                                                aacFrameSize :: !Word64}
+data instance  Audio r c (Aac aot) = MkAacBuffer{aacFrameMediaData
+                                                 :: !(V.Vector Word8),
+                                                 aacFrameDuration :: !(Ticks64 r)}
                                    deriving (Generic)
 
 instance (KnownRate r, KnownChannelLayout c, Show (AacAotProxy aot)) =>
@@ -82,24 +79,25 @@
 
 instance (KnownRate r) =>
          HasDuration (Audio r c (Aac aot)) where
-  getDuration MkAacFrame {aacFrameSize} =
-    from nominalDiffTime # (MkTicks aacFrameSize :: Ticks r Word64)
-  getDurationTicks MkAacFrame {aacFrameSize} =
-    convertTicks (MkTicks aacFrameSize :: Ticks r Word64)
+  getDuration MkAacBuffer {aacFrameDuration} =
+    from nominalDiffTime # aacFrameDuration
+  getDurationTicks MkAacBuffer {aacFrameDuration} =
+    convertTicks aacFrameDuration
 
 instance NFData (Audio r c (Aac aot))
 
 instance (KnownRate r, KnownChannelLayout c, Show (AacAotProxy aot)) =>
          Show (Audio r c (Aac aot)) where
-  showsPrec d MkAacFrame {aacFrameMediaData, aacFrameSize} =
+  showsPrec d MkAacBuffer {aacFrameMediaData, aacFrameDuration} =
     showParen
       (d > 10)
       (showString "aac frame: " .
        showsPrec 11 (MkShowMedia :: MediaDescription (Audio r c (Aac aot))) .
        showString ", samples: " .
-       shows aacFrameSize .
+       shows aacFrameDuration .
        showString ", data: " .
-       showsPrec 11 (V.length aacFrameMediaData) . showString " bytes starting with: " .
+       showsPrec 11 (V.length aacFrameMediaData) .
+       showString " bytes starting with: " .
        showsPrec 11 (V.take 16 aacFrameMediaData))
 
 instance (KnownRate r, KnownChannelLayout c, Show (AacAotProxy aot)) =>
@@ -179,7 +177,7 @@
   , _aacEncoderInfoId :: String
   -- ^ Identification string for one specific encoder, derived from the natice
   -- C pointer in 'encoderHandle'.
-  } deriving Generic
+  } deriving (Generic)
 
 instance NFData (AacEncoderInfo r c a)
 
@@ -295,19 +293,11 @@
       return (Tagged enc, i)
 
 -- * Stateful Encoding
-
--- | Type alias for the internal RWS monad of the aac encoder.
-type AacEncT rate channels aot m a = RWST Encoder () (AacEncSt rate channels aot) m a
-
--- | The internal state for 'encodeLinearToAac'
-newtype AacEncSt (rate :: Rate) channels (aot :: AacAot) = MkAacEncSt
-  { _numberOfDelayedSamples :: Word64
-  -- ^ The number of input samples currently buffered in the delay lines of the encoder.
-  } deriving (Show)
+-- | Type alias for the internal ReaderT monad of the aac encoder.
+type AacEncT rate channels aot m a = ReaderT Encoder m a
 
--- | An internal 'Iso' for the 'AacEncSt'
-numberOfDelayedSamples :: Iso' (AacEncSt (rate :: Rate) channels (aot :: AacAot)) Word64
-numberOfDelayedSamples = iso _numberOfDelayedSamples MkAacEncSt
+-- | Aac encoded 'Frame's
+type AacFrame rate channels aot = Frame () () (Audio rate channels (Aac aot))
 
 -- | Convert linear audio to AAC encoded audio with the given encoder settings.
 encodeLinearToAac
@@ -320,17 +310,17 @@
      , MonadThrow m
      , MonadLogger m
      )
-  => Audio rate channels (Raw S16)
-  -> AacEncT rate channels aot m [Audio rate channels (Aac aot)]
-encodeLinearToAac !aIn =
+  => Frame someSeq someTicks (Audio rate channels (Raw S16))
+  -> AacEncT rate channels aot m [AacFrame rate channels aot]
+encodeLinearToAac (MkFrame _ _ !aIn) =
   let dIn = V.unsafeCast (aIn ^. mediaBuffer . mediaBufferVector)
-  in encodeSampleVector dIn []
+  in encodeAllFrames dIn []
 
--- | Convert linear audio to AAC encoded audio with the given encoder settings,
+-- | (Internal) Convert linear audio to AAC encoded audio with the given encoder settings,
 -- from a raw sample vector.
--- If the sample vector contains more that the encoder can swallow at a time,
--- the encoder is repeatedly called until all input is consumed.
-encodeSampleVector
+-- If the input contains more than 'frameSize' samples per channel, recurse
+-- until all input is consumed and return the generated frames.
+encodeAllFrames
   :: forall m channels rate aot.
      ( MonadLogger m
      , MonadIO m
@@ -341,9 +331,9 @@
      , V.Storable (Pcm channels S16)
      )
   => V.Vector Word16
-  -> [Audio rate channels (Aac aot)]
-  -> AacEncT rate channels aot m [Audio rate channels (Aac aot)]
-encodeSampleVector dIn acc
+  -> [AacFrame rate channels aot]
+  -> AacEncT rate channels aot m [AacFrame rate channels aot]
+encodeAllFrames dIn acc
   | V.length dIn <= 0 = return []
   | otherwise = do
     e <- ask
@@ -352,7 +342,12 @@
       Left err -> do
         $logError (fromString (printf "encoding failed: %s" (show err)))
         throwM err
-      Right fr -> returnAccOrEncodeAgain acc fr
+      Right MkEncodeResultEof -> return (reverse acc)
+      Right MkEncodeResult {encodeResultLeftOverInput, encodeResultSamples} -> do
+        acc' <- appendNextFrame acc encodeResultSamples
+        case encodeResultLeftOverInput of
+          Nothing -> return (reverse acc')
+          Just rest -> encodeAllFrames rest acc'
 
 -- | Flush any left over input and then also flush delay lines of the AAC encoder.
 flushAacEncoder
@@ -364,47 +359,57 @@
      , Show (AacAotProxy aot)
      , V.Storable (Pcm channels S16)
      )
-  => AacEncT r channels aot m [Audio r channels (Aac aot)]
+  => AacEncT r channels aot m [AacFrame r channels aot]
 flushAacEncoder = do
-  d <- use numberOfDelayedSamples
+  $logDebug "flushing"
+  flushLoop []
+ where
+   flushLoop acc = do
+     e <- ask
+     eres <- liftIO $ flush e
+     case eres of
+       Left err -> do
+         $logError (fromString (printf "flushing failed: %s" (show err)))
+         throwM err
+       Right MkEncodeResultEof -> do
+         $logInfo "flushed"
+         return (reverse acc)
+       Right MkEncodeResult {encodeResultSamples} -> do
+         acc' <- appendNextFrame acc encodeResultSamples
+         flushUntilEof acc'
+
+
+
+-- | (Internal) Flush until the encoder returns the EOF return code.
+flushUntilEof
+  :: (MonadThrow m, MonadLogger m, MonadIO m)
+  => [AacFrame r channels aot]
+  -> AacEncT r channels aot m [AacFrame r channels aot]
+flushUntilEof acc = do
   e <- ask
-  $logDebug (fromString (printf "flushing %d samples" d))
   eres <- liftIO $ flush e
   case eres of
     Left err -> do
       $logError (fromString (printf "flushing failed: %s" (show err)))
       throwM err
-    Right fr -> do
-      $logInfo (fromString (printf "flushed frame: %s" (show fr)))
-      returnAccOrEncodeAgain [] fr
+    Right MkEncodeResultEof -> do
+      $logInfo "flushed"
+      return (reverse acc)
+    Right MkEncodeResult {encodeResultSamples} -> do
+      acc' <- appendNextFrame acc encodeResultSamples
+      flushUntilEof acc'
 
--- | Internal function
-returnAccOrEncodeAgain
-  :: ( MonadLogger m
-     , MonadIO m
-     , MonadThrow m
-     , KnownChannelLayout channels
-     , KnownRate rate
-     , Show (AacAotProxy aot)
-     , V.Storable (Pcm channels S16)
-     )
-  => [Audio rate channels (Aac aot)]
-  -> EncodeResult
-  -> AacEncT rate channels aot m [Audio rate channels (Aac aot)]
-returnAccOrEncodeAgain acc MkEncodeResult { encodeResultLeftOverInput
-                                          , encodeResultSamples
-                                          , encodeResultConsumedFrames
-                                          } = do
-  numberOfDelayedSamples += encodeResultConsumedFrames
-  delayed <- use numberOfDelayedSamples
-  let acc' = maybe acc (\es -> MkAacFrame es encoded : acc) encodeResultSamples
-      encoded =
-        if isJust encodeResultSamples
-          then delayed
-          else 0
-  numberOfDelayedSamples -= encoded
-  case encodeResultLeftOverInput of
-    Nothing -> return (reverse acc')
-    Just rest -> encodeSampleVector rest acc'
+-- | (Internal) Create a new 'Frame' and increment the sequence number and
+--   update the timestamp from 'AacEncSt'
+appendNextFrame
+  :: Monad m
+  => [AacFrame rate channels aot]
+  -> Maybe (V.Vector Word8)
+  -> AacEncT rate channels aot m [AacFrame rate channels aot]
+appendNextFrame acc = maybe (return acc) (\es -> (: acc) <$> mkNextFrame es)
+  where
+    mkNextFrame es = do
+      len <- fromIntegral <$> asks frameSize
+      return (MkFrame () () (MkAacBuffer es len))
 
 makeLenses ''AacEncoderInfo
diff --git a/src/Data/MediaBus/FdkAac/EncoderFdkWrapper.hs b/src/Data/MediaBus/FdkAac/EncoderFdkWrapper.hs
--- a/src/Data/MediaBus/FdkAac/EncoderFdkWrapper.hs
+++ b/src/Data/MediaBus/FdkAac/EncoderFdkWrapper.hs
@@ -376,53 +376,56 @@
   -> IO (Either EncodeFailure EncodeResult)
 toEncodeResult vec MkEncoder {unsafeOutBuffer, channelCount} ((numOutBytes, numInSamples, numAncBytes), retCode) =
   let retCode' = toAacEncErrorCode retCode
-  in
-    if retCode' /= AacEncOk && retCode' /= AacEncEncodeEof 
-    then return $
-         Left
-           MkEncodeFailure
-           { encodeFailureCode = toAacEncErrorCode retCode
-           , encodeFailureNumOutBytes = fromIntegral numOutBytes
-           , encodeFailureNumInSamples = fromIntegral numInSamples
-           , encodeFailureNumAncBytes = fromIntegral numAncBytes
-           }
-    else do
-      let !numInSamplesI = fromIntegral numInSamples
-          !consumedFrames =
-            fromIntegral numInSamplesI `div` fromIntegral channelCount
-          !leftOverInput =
-            if numInSamplesI >= V.length vec
-              then Nothing
-              else let !inSliceLen = V.length vec - numInSamplesI
-                       !inSlice = V.slice numInSamplesI inSliceLen vec
-                   in Just inSlice
-          !numOutBytesI = fromIntegral numOutBytes
-      !encodedOutput <-
-        if numOutBytesI == 0
-          then return Nothing
-          else do
-            !outTooLarge <- V.freeze unsafeOutBuffer
-            return $ Just $ V.force $ V.slice 0 numOutBytesI outTooLarge
-      return $
-        Right
-          MkEncodeResult
-          { encodeResultConsumedFrames = consumedFrames
-          , encodeResultLeftOverInput = coerce leftOverInput
-          , encodeResultSamples = coerce encodedOutput
-          }
+  in if retCode' == AacEncEncodeEof
+       then return (Right MkEncodeResultEof)
+       else if retCode' /= AacEncOk
+              then return $
+                   Left
+                     MkEncodeFailure
+                     { encodeFailureCode = toAacEncErrorCode retCode
+                     , encodeFailureNumOutBytes = fromIntegral numOutBytes
+                     , encodeFailureNumInSamples = fromIntegral numInSamples
+                     , encodeFailureNumAncBytes = fromIntegral numAncBytes
+                     }
+              else do
+                let !numInSamplesI = fromIntegral numInSamples
+                    !consumedFrames =
+                      fromIntegral numInSamplesI `div` fromIntegral channelCount
+                    !leftOverInput =
+                      if numInSamplesI >= V.length vec
+                        then Nothing
+                        else let !inSliceLen = V.length vec - numInSamplesI
+                                 !inSlice = V.slice numInSamplesI inSliceLen vec
+                             in Just inSlice
+                    !numOutBytesI = fromIntegral numOutBytes
+                !encodedOutput <-
+                  if numOutBytesI == 0
+                    then return Nothing
+                    else do
+                      !outTooLarge <- V.freeze unsafeOutBuffer
+                      return $
+                        Just $ V.force $ V.slice 0 numOutBytesI outTooLarge
+                return $
+                  Right
+                    MkEncodeResult
+                    { encodeResultConsumedFrames = consumedFrames
+                    , encodeResultLeftOverInput = coerce leftOverInput
+                    , encodeResultSamples = coerce encodedOutput
+                    }
 
 -- | Result of 'encode'
-data EncodeResult = MkEncodeResult
-  { encodeResultConsumedFrames :: !Word64 -- ^ Number of samples from the input
+data EncodeResult
+  = MkEncodeResultEof
+  | MkEncodeResult { encodeResultConsumedFrames :: !Word64 -- ^ Number of samples from the input
                                          -- that were processed by the encoder
-  , encodeResultLeftOverInput :: !(Maybe (V.Vector Word16)) -- ^ The unprocessed
+                  ,  encodeResultLeftOverInput :: !(Maybe (V.Vector Word16)) -- ^ The unprocessed
                                                            -- rest of the input.
                                                            -- Only if the input
                                                            -- is larger than the
                                                            -- encoders frame
                                                            -- length a left over
                                                            -- is returned.
-  , encodeResultSamples :: !(Maybe (V.Vector Word8)) -- ^ Encoded output. If less
+                  ,  encodeResultSamples :: !(Maybe (V.Vector Word8)) -- ^ Encoded output. If less
                                                     -- than the frame length
                                                     -- samples have been
                                                     -- encoded, then the result
@@ -432,9 +435,10 @@
                                                     -- representing the encded
                                                     -- samples delayed by
                                                     -- 'frameLength'.
-  }
+                   }
 
 instance Show EncodeResult where
+  showsPrec _ MkEncodeResultEof = showString "encoder-EOF"
   showsPrec d MkEncodeResult { encodeResultConsumedFrames
                              , encodeResultLeftOverInput
                              , encodeResultSamples
