-- | A single-track AAC audio streaming utility wrapping 'AudioFile' for
-- streaming via e.g. DASH.
module Data.ByteString.Mp4.AacInitSegment
  ( AacInitSegment(..)
  , BinaryAacInitSegment(..)
  , buildAacInitSegment
  ) where

import qualified Data.ByteString as BS
import Data.ByteString.IsoBaseFileFormat.Box
import Data.ByteString.IsoBaseFileFormat.Boxes
import Data.ByteString.IsoBaseFileFormat.Brands.Dash as X
import Data.ByteString.IsoBaseFileFormat.MediaFile as X
import Data.ByteString.IsoBaseFileFormat.ReExports as X
import Data.ByteString.IsoBaseFileFormat.Util.BoxFields as X
import Data.ByteString.IsoBaseFileFormat.Util.Time
import Data.ByteString.IsoBaseFileFormat.Util.Versioned
import qualified Data.ByteString.Lazy as BL
import Data.ByteString.Mp4.Boxes.AudioSpecificConfig
import Data.ByteString.Mp4.Boxes.Mp4AudioSampleEntry as X
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE

-- | Initialisation segment parameters of an aac audio stream mp4 file.
data AacInitSegment = AacInitSegment
  { creationTime :: !(TS32 "creation_time")
  , trackName :: !String
  , useHeAac :: !Bool
  , sampleRate :: !SamplingFreqTable
  , channelConfig :: !ChannelConfigTable
  }

instance Show BinaryAacInitSegment where
  show (BinaryAacInitSegment !d) =
    printf "INIT SEGMENT - size: %14d" (BS.length d)

-- | Encoded, binary MP4 AAC init segment (strict).
newtype BinaryAacInitSegment = BinaryAacInitSegment
  { fromBinaryAacInitSegment :: BS.ByteString
  }

-- | Convert an 'AacInitSegment' record to a generic 'BinaryAacInitSegment'.
buildAacInitSegment :: AacInitSegment -> BinaryAacInitSegment
buildAacInitSegment =
  BinaryAacInitSegment . BL.toStrict . toLazyByteString . build

-- | Convert an 'AacInitSegment' record to a generic 'BinaryAacInitSegment'.
build :: AacInitSegment -> Builder
build AacInitSegment {..} =
  let timeScaleForSampleRate = TimeScale (sampleRateToNumber sampleRate)
  in mediaBuilder dash $
      -- TODO must be iso5 for the way we use elementary stream descriptors
     fileTypeBox (FileType "iso5" 0 ["isom", "iso5", "dash", "mp42"]) :.
     skipBox
       (Skip
          (TE.encodeUtf8
             (T.pack "Lindenbaum GmbH, isobmff, Sven Heyll 2019"))) :|
     movie
       (movieHeader
          (MovieHeader $
           V0 (creationTime :+ relabelScalar creationTime :+ def :+ TSv0 0) :+
           def :+
           def :+
           def :+
           def :+
           def :+
           def :+
           Custom (Scalar 2)) :.
        track
          (trackHeader
             TrackInMovieAndPreview
             (TrackHeader $
              V0
                (creationTime :+ relabelScalar creationTime :+ 1 :+ Constant :+
                 0) :+
              def) :|
           media
             (mediaHeader
                (MediaHeader $
                 V0
                   (creationTime :+ relabelScalar creationTime :+
                    timeScaleForSampleRate :+
                    TSv0 0) :+
                 def) :.
              handler (namedAudioTrackHandler (T.pack trackName)) :|
              mediaInformation
                (soundMediaHeader (SoundMediaHeader def) :.
                 (dataInformation $: localMediaDataReference) :|
                 sampleTable
                   ((sampleDescription $:
                     audioSampleEntry
                       1
                       (aacAudioSampleEntrySimple
                          useHeAac
                          sampleRate
                          channelConfig
                          (Scalar 16)) :.
                     timeToSample [] :.
                     sampleToChunk [] :.
                     fixedSampleSize 0 0 :|
                     chunkOffset32 []))))) :|
        (movieExtends $: trackExtendsUnknownDuration 1 1))