{-# LANGUAGE UndecidableInstances #-}

-- | @mp4a@ Audio sample entry according to ISO 14496-14
module Data.ByteString.Mp4.Boxes.Mp4AudioSampleEntry where

import Data.ByteString.IsoBaseFileFormat.Box
import Data.ByteString.IsoBaseFileFormat.Boxes
import Data.ByteString.IsoBaseFileFormat.ReExports
import Data.ByteString.IsoBaseFileFormat.Util.BoxContent
import Data.ByteString.IsoBaseFileFormat.Util.BoxFields
import Data.ByteString.Mp4.Boxes.AudioSpecificConfig
import Data.ByteString.Mp4.Boxes.DecoderConfigDescriptor
import Data.ByteString.Mp4.Boxes.DecoderSpecificInfo
import Data.ByteString.Mp4.Boxes.ElementaryStreamDescriptor

-- | A /body/ for 'AudioSampleEntry'. This 'IsBoxContent' with an
-- 'ElementaryStreamDescriptor' for ISO-14496-3 audio, with audio decoder
-- specific info.

-- | Create an 'AudioSampleEntry' with an 'AudioEsd'
audioSampleEntry ::
  U16 "data_reference_index" ->
  AudioSampleEntry AudioEsd ->
  Box (SampleEntry (AudioSampleEntry AudioEsd))
audioSampleEntry = sampleEntry

type instance BoxTypeSymbol AudioEsd = "mp4a"

-- | Create an mp4 audio elementary stream descriptor full box
aacAudioSampleEntrySimple ::
  Bool ->
  SamplingFreqTable ->
  ChannelConfigTable ->
  U16 "samplesize" ->
  AudioSampleEntry AudioEsd
aacAudioSampleEntrySimple sbr sf cc sampleSize =
  AudioSampleEntry
    ( Constant
        :+ Custom (Scalar (channelConfigToNumber cc))
        :+ Custom sampleSize
        :+ 0
        :+ Constant
        :+ Custom (Scalar (sampleRateToNumber sf * 65536))
        :+ mkAudioEsdAacLcOrHeAac sbr sf cc
    )

mkAudioEsdAacLcOrHeAac ::
  Bool ->
  SamplingFreqTable ->
  ChannelConfigTable ->
  AudioEsd
mkAudioEsdAacLcOrHeAac False sf cc =
  AudioEsd
    ( esdBox
        (Proxy @Mp4AacLcEsDescriptor)
        False
        0
        0
        0
        (sampleRateToEnum sf)
        (channelConfigToEnum cc)
    )
mkAudioEsdAacLcOrHeAac True sf cc =
  AudioEsd
    ( esdBox
        (Proxy @Mp4HeAacEsDescriptor)
        False
        0
        0
        0
        (sampleRateToEnum sf)
        (channelConfigToEnum cc)
        (sampleRateToEnum sf)
    )

-- | Consists of an 'ElementaryStreamDescriptor' derived from a 'DecoderSpecificInfo'.
newtype AudioEsd
  = AudioEsd EsdBox
  deriving (IsBoxContent)

type Mp4AacLcEsDescriptor =
  ESDescriptorMp4File
    DefaultEsId
    ( Mp4AacAudioDecoderConfigDescriptor
        ( AudioConfigAacLc
            (EnumParam "samplingFreq" SamplingFreq)
            (EnumParam "channelConfig" ChannelConfig)
        )
    )

type Mp4HeAacEsDescriptor =
  ESDescriptorMp4File
    DefaultEsId
    ( Mp4AacAudioDecoderConfigDescriptor
        ( AudioConfigHeAac
            (EnumParam "samplingFreq" SamplingFreq)
            (EnumParam "channelConfig" ChannelConfig)
        )
    )

type Mp4AacAudioDecoderConfigDescriptor cfg =
  DecoderConfigDescriptor
    'AudioIso14496_3
    'AudioStream
    '[cfg]
    '[]
