HaishinKit.swift/Sources/MPEG/AudioSpecificConfig.swift

212 lines
6.4 KiB
Swift

import AVFoundation
/**
The Audio Specific Config is the global header for MPEG-4 Audio
- seealso: http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Audio_Specific_Config
- seealso: http://wiki.multimedia.cx/?title=Understanding_AAC
*/
struct AudioSpecificConfig {
static let ADTSHeaderSize: Int = 7
enum AudioObjectType: UInt8 {
case unknown = 0
case aacMain = 1
case aaclc = 2
case aacssr = 3
case aacltp = 4
case aacsbr = 5
case aacScalable = 6
case twinqVQ = 7
case celp = 8
case hxvc = 9
init(objectID: MPEG4ObjectID) {
switch objectID {
case .aac_Main:
self = .aacMain
case .AAC_LC:
self = .aaclc
case .AAC_SSR:
self = .aacssr
case .AAC_LTP:
self = .aacltp
case .AAC_SBR:
self = .aacsbr
case .aac_Scalable:
self = .aacScalable
case .twinVQ:
self = .twinqVQ
case .CELP:
self = .celp
case .HVXC:
self = .hxvc
@unknown default:
self = .unknown
}
}
}
enum SamplingFrequency: UInt8 {
case hz96000 = 0
case hz88200 = 1
case hz64000 = 2
case hz48000 = 3
case hz44100 = 4
case hz32000 = 5
case hz24000 = 6
case hz22050 = 7
case hz16000 = 8
case hz12000 = 9
case hz11025 = 10
case hz8000 = 11
case hz7350 = 12
var sampleRate: Float64 {
switch self {
case .hz96000:
return 96000
case .hz88200:
return 88200
case .hz64000:
return 64000
case .hz48000:
return 48000
case .hz44100:
return 44100
case .hz32000:
return 32000
case .hz24000:
return 24000
case .hz22050:
return 22050
case .hz16000:
return 16000
case .hz12000:
return 12000
case .hz11025:
return 11025
case .hz8000:
return 8000
case .hz7350:
return 7350
}
}
init(sampleRate: Float64) {
switch Int(sampleRate) {
case 96000:
self = .hz96000
case 88200:
self = .hz88200
case 64000:
self = .hz64000
case 48000:
self = .hz48000
case 44100:
self = .hz44100
case 32000:
self = .hz32000
case 24000:
self = .hz24000
case 22050:
self = .hz22050
case 16000:
self = .hz16000
case 12000:
self = .hz12000
case 11025:
self = .hz11025
case 8000:
self = .hz8000
case 7350:
self = .hz7350
default:
self = .hz44100
}
}
}
enum ChannelConfiguration: UInt8 {
case definedInAOTSpecificConfig = 0
case frontCenter = 1
case frontLeftAndFrontRight = 2
case frontCenterAndFrontLeftAndFrontRight = 3
case frontCenterAndFrontLeftAndFrontRightAndBackCenter = 4
case frontCenterAndFrontLeftAndFrontRightAndBackLeftAndBackRight = 5
case frontCenterAndFrontLeftAndFrontRightAndBackLeftAndBackRightLFE = 6
case frontCenterAndFrontLeftAndFrontRightAndSideLeftAndSideRightAndBackLeftAndBackRightLFE = 7
}
let type: AudioObjectType
let frequency: SamplingFrequency
let channel: ChannelConfiguration
let frameLengthFlag = false
var bytes: [UInt8] {
var bytes = [UInt8](repeating: 0, count: 2)
bytes[0] = type.rawValue << 3 | (frequency.rawValue >> 1)
bytes[1] = (frequency.rawValue & 0x1) << 7 | (channel.rawValue & 0xF) << 3
return bytes
}
init?(bytes: [UInt8]) {
guard
let type = AudioObjectType(rawValue: bytes[0] >> 3),
let frequency = SamplingFrequency(rawValue: (bytes[0] & 0b00000111) << 1 | (bytes[1] >> 7)),
let channel = ChannelConfiguration(rawValue: (bytes[1] & 0b01111000) >> 3) else {
return nil
}
self.type = type
self.frequency = frequency
self.channel = channel
}
init(type: AudioObjectType, frequency: SamplingFrequency, channel: ChannelConfiguration) {
self.type = type
self.frequency = frequency
self.channel = channel
}
init(formatDescription: CMFormatDescription) {
let asbd: AudioStreamBasicDescription = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription)!.pointee
type = AudioObjectType(objectID: MPEG4ObjectID(rawValue: Int(asbd.mFormatFlags))!)
frequency = SamplingFrequency(sampleRate: asbd.mSampleRate)
channel = ChannelConfiguration(rawValue: UInt8(asbd.mChannelsPerFrame))!
}
func adts(_ length: Int) -> [UInt8] {
let size = 7
let fullSize: Int = size + length
var adts = [UInt8](repeating: 0x00, count: size)
adts[0] = 0xFF
adts[1] = 0xF9
adts[2] = (type.rawValue - 1) << 6 | (frequency.rawValue << 2) | (channel.rawValue >> 2)
adts[3] = (channel.rawValue & 3) << 6 | UInt8(fullSize >> 11)
adts[4] = UInt8((fullSize & 0x7FF) >> 3)
adts[5] = ((UInt8(fullSize & 7)) << 5) + 0x1F
adts[6] = 0xFC
return adts
}
func audioStreamBasicDescription() -> AudioStreamBasicDescription {
AudioStreamBasicDescription(
mSampleRate: frequency.sampleRate,
mFormatID: kAudioFormatMPEG4AAC,
mFormatFlags: UInt32(type.rawValue),
mBytesPerPacket: 0,
mFramesPerPacket: frameLengthFlag ? 960 : 1024,
mBytesPerFrame: 0,
mChannelsPerFrame: UInt32(channel.rawValue),
mBitsPerChannel: 0,
mReserved: 0
)
}
}
extension AudioSpecificConfig: CustomDebugStringConvertible {
// MARK: CustomDebugStringConvertible
var debugDescription: String {
Mirror(reflecting: self).debugDescription
}
}