packages feed

mediabus-fdk-aac-0.4.0.0: src/Data/MediaBus/FdkAac/Conduit/Encoder.hs

{-# LANGUAGE RankNTypes #-}

-- | This module defines a conduit to encode linear audio into AAC.
module Data.MediaBus.FdkAac.Conduit.Encoder
  ( encodeLinearToAacC
  ) where

import Conduit
import Control.Monad.Logger
import Data.MediaBus
import Data.MediaBus.FdkAac.Encoder
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.
-- 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 m.
     ( MonadLoggerIO m
     , MonadThrow m
     , MonadResource m
     , KnownChannelLayout channels
     , KnownRate r
     , Typeable r
     , Show (AacAotProxy aot)
     , KnownNat (GetAacAot aot)
     , Show i
     , CanBeSample (Pcm channels S16)
     , Show (Pcm channels S16)
     )
  => AacEncoderConfig r channels 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
  prefixLogsC (show enc ++ " - ") $ runReaderC enc (encodeThenFlush info)
  where
    encodeThenFlush info = do
      awaitForever go
      aacs <- lift flushAacEncoder
      Prelude.mapM_ yieldNextFrame aacs
      where
        go (MkStream (Next f)) = do
          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