/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
        File:		ALACAudioTypes.h
*/

#ifndef ALACAUDIOTYPES_H
#define ALACAUDIOTYPES_H

#if PRAGMA_ONCE
#pragma once
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if PRAGMA_STRUCT_ALIGN
#pragma options align = mac68k
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
#pragma pack(2)
#endif

#include <stdint.h>

#if defined(__ppc__)
#define TARGET_RT_BIG_ENDIAN 1
#elif defined(__ppc64__)
#define TARGET_RT_BIG_ENDIAN 1
#endif

#define kChannelAtomSize 12

enum {
    kALAC_UnimplementedError = -4,
    kALAC_FileNotFoundError  = -43,
    kALAC_ParamError         = -50,
    kALAC_MemFullError       = -108
};

enum {
    kALACFormatAppleLossless = 'a' << 24 | 'l' << 16 | 'a' << 8 | 'c',
    kALACFormatLinearPCM     = 'l' << 24 | 'p' << 16 | 'c' << 8 | 'm',
};

enum {
    kALACMaxChannels            = 8,
    kALACMaxEscapeHeaderBytes   = 8,
    kALACMaxSearches            = 16,
    kALACMaxCoefs               = 16,
    kALACDefaultFramesPerPacket = 4096
};

typedef uint32_t ALACChannelLayoutTag;

enum {
    kALACFormatFlagIsFloat         = (1 << 0), // 0x1
    kALACFormatFlagIsBigEndian     = (1 << 1), // 0x2
    kALACFormatFlagIsSignedInteger = (1 << 2), // 0x4
    kALACFormatFlagIsPacked        = (1 << 3), // 0x8
    kALACFormatFlagIsAlignedHigh   = (1 << 4), // 0x10
};

enum {
#if TARGET_RT_BIG_ENDIAN
    kALACFormatFlagsNativeEndian = kALACFormatFlagIsBigEndian
#else
    kALACFormatFlagsNativeEndian = 0
#endif
};

// this is required to be an IEEE 64bit float
typedef double alac_float64_t;

// These are the Channel Layout Tags used in the Channel Layout Info portion of the ALAC magic cookie
enum {
    kALACChannelLayoutTag_Mono       = (100 << 16) | 1, // C
    kALACChannelLayoutTag_Stereo     = (101 << 16) | 2, // L R
    kALACChannelLayoutTag_MPEG_3_0_B = (113 << 16) | 3, // C L R
    kALACChannelLayoutTag_MPEG_4_0_B = (116 << 16) | 4, // C L R Cs
    kALACChannelLayoutTag_MPEG_5_0_D = (120 << 16) | 5, // C L R Ls Rs
    kALACChannelLayoutTag_MPEG_5_1_D = (124 << 16) | 6, // C L R Ls Rs LFE
    kALACChannelLayoutTag_AAC_6_1    = (142 << 16) | 7, // C L R Ls Rs Cs LFE
    kALACChannelLayoutTag_MPEG_7_1_B = (127 << 16) | 8  // C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
};

// ALAC currently only utilizes these channels layouts. There is a one for one correspondance between a
// given number of channels and one of these layout tags
static const ALACChannelLayoutTag ALACChannelLayoutTags[kALACMaxChannels] = {
    kALACChannelLayoutTag_Mono,       // C
    kALACChannelLayoutTag_Stereo,     // L R
    kALACChannelLayoutTag_MPEG_3_0_B, // C L R
    kALACChannelLayoutTag_MPEG_4_0_B, // C L R Cs
    kALACChannelLayoutTag_MPEG_5_0_D, // C L R Ls Rs
    kALACChannelLayoutTag_MPEG_5_1_D, // C L R Ls Rs LFE
    kALACChannelLayoutTag_AAC_6_1,    // C L R Ls Rs Cs LFE
    kALACChannelLayoutTag_MPEG_7_1_B  // C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
};

// AudioChannelLayout from CoreAudioTypes.h. We never need the AudioChannelDescription so we remove it
struct ALACAudioChannelLayout
{
    ALACChannelLayoutTag mChannelLayoutTag;
    uint32_t             mChannelBitmap;
    uint32_t             mNumberChannelDescriptions;
};
typedef struct ALACAudioChannelLayout ALACAudioChannelLayout;

struct AudioFormatDescription
{
    alac_float64_t mSampleRate;
    uint32_t       mFormatID;
    uint32_t       mFormatFlags;
    uint32_t       mBytesPerPacket;
    uint32_t       mFramesPerPacket;
    uint32_t       mBytesPerFrame;
    uint32_t       mChannelsPerFrame;
    uint32_t       mBitsPerChannel;
    uint32_t       mReserved;
};
typedef struct AudioFormatDescription AudioFormatDescription;

/* Lossless Definitions */

enum {
    kALACCodecFormat       = 'a' << 24 | 'l' << 16 | 'a' << 8 | 'c',
    kALACVersion           = 0,
    kALACCompatibleVersion = kALACVersion,
    kALACDefaultFrameSize  = 4096
};

// note: this struct is wrapped in an 'alac' atom in the sample description extension area
// note: in QT movies, it will be further wrapped in a 'wave' atom surrounded by 'frma' and 'term' atoms
typedef struct ALACSpecificConfig
{
    uint32_t frameLength;
    uint8_t  compatibleVersion;
    uint8_t  bitDepth; // max 32
    uint8_t  pb;       // 0 <= pb <= 255
    uint8_t  mb;
    uint8_t  kb;
    uint8_t  numChannels;
    uint16_t maxRun;
    uint32_t maxFrameBytes;
    uint32_t avgBitRate;
    uint32_t sampleRate;

} ALACSpecificConfig;

// The AudioChannelLayout atom type is not exposed yet so define it here
enum {
    AudioChannelLayoutAID = 'c' << 24 | 'h' << 16 | 'a' << 8 | 'n',
};

#if PRAGMA_STRUCT_ALIGN
#pragma options align = reset
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
#pragma pack()
#endif

#ifdef __cplusplus
}
#endif

#endif /* ALACAUDIOTYPES_H */
