-
Notifications
You must be signed in to change notification settings - Fork 0
/
AudioDecoder.swift
145 lines (117 loc) · 4.56 KB
/
AudioDecoder.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//
// AudioDecoder.swift
// Apple4ChannelBug
//
// Created by Tim Hoogstrate on 22/03/2019.
// Copyright © 2019 Tim Hoogstrate. All rights reserved.
//
import UIKit
import CoreAudio
import AudioToolbox
import AVFoundation
public class TSAudioDecoder {
private var sampleRate:Float64 = 44100
private var numberOfChannels:UInt32 = 1
private(set) var status: OSStatus = noErr {
didSet {
if status != noErr {
if status == 1718449215 {
print("Audio decoder status: \(self.status) \(numberOfChannels) channel audio")
} else {
print("Audio decoder status: \(self.status)")
}
}
}
}
private var outputCallback: AudioQueueOutputCallback = {(
inUserData: UnsafeMutableRawPointer?,
inAQ: AudioQueueRef,
inBuffer: AudioQueueBufferRef) in
print("Finished playing audio sample")
}
var counter = 0
public func addAudioSamplesToQueue(audioSample: AudioSample) {
if queue == nil {
return
}
guard buffers.count > 0 else {
return
}
let buffer = buffers[counter]
// Copy encoded data into AudioQueue memory
memcpy(buffer!.pointee.mAudioData, audioSample.audioData, audioSample.audioData.count)
// Create audioStreamPacketDexcription to go along with this packet.
var description = AudioStreamPacketDescription.init(mStartOffset: 0,
mVariableFramesInPacket: 1024,
mDataByteSize: UInt32(audioSample.audioData.count))
// Set the encoded data size on the buffer
buffer!.pointee.mAudioDataByteSize = UInt32(audioSample.audioData.count)
// Enqueue buffer into decoder
status = AudioQueueEnqueueBuffer(queue!, buffer!, 1, UnsafeMutablePointer<AudioStreamPacketDescription>(&description))
counter+=1
if counter == defaultNumberOfBuffers {
counter = 0
}
}
public func startSession(audioSample: AudioSample) {
setParameters(audioSample: audioSample)
initializeForAudioQueue()
startQueueIfNeed()
if buffers.count != defaultNumberOfBuffers {
createBuffers()
}
addAudioSamplesToQueue(audioSample:audioSample)
}
private func setParameters(audioSample: AudioSample) {
numberOfChannels = audioSample.channels
sampleRate = audioSample.sampleRate
}
func initializeForAudioQueue() {
fileTypeHint = kAudioFileAAC_ADTSType
var inDesc = AudioStreamBasicDescription(mSampleRate: sampleRate, mFormatID: kAudioFormatMPEG4AAC, mFormatFlags: 2, mBytesPerPacket: 0, mFramesPerPacket: 1024, mBytesPerFrame: 0, mChannelsPerFrame: numberOfChannels, mBitsPerChannel: 0, mReserved: 0)
var queue: AudioQueueRef? = nil
status = AudioQueueNewOutput(
&inDesc,
outputCallback,
unsafeBitCast(self, to: UnsafeMutableRawPointer.self),
nil,
CFRunLoopMode.commonModes.rawValue,
0,
&queue)
// print("BUFFERS MADE STATUS: \(status)")
self.queue = queue
}
private var queue: AudioQueueRef? = nil
func startQueueIfNeed() {
guard let queue: AudioQueueRef = queue else {
return
}
status = AudioQueuePrime(queue, 0, nil)
status = AudioQueueStart(queue, nil)
print("AudioQueueStart: \(status)")
}
func createBuffers() {
guard queue != nil else {
return
}
if buffers.count != defaultNumberOfBuffers {
for _ in 0..<defaultNumberOfBuffers {
var buffer: AudioQueueBufferRef? = nil
status = AudioQueueAllocateBuffer(queue!, defaultBufferSize, &buffer)
if status != 0 {
return
}
buffers.append(buffer)
}
}
}
private var started: Bool = false
var runloop: CFRunLoop?
let defaultNumberOfBuffers: Int = 128
let defaultBufferSize: UInt32 = 128 * 5000
private var buffers: [AudioQueueBufferRef?] = []
private var current: Int = 0
private var packetDescriptions: [AudioStreamPacketDescription] = []
private var fileStreamID: AudioFileStreamID? = nil
var fileTypeHint: AudioFileTypeID?
}