Created
February 22, 2024 00:57
-
-
Save levs42/9fefd10977a71c7eb05251dcc40d4dae to your computer and use it in GitHub Desktop.
Basic audio player with a buffer callback in Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import AVFoundation | |
import CoreMedia | |
import CoreAudio | |
protocol AudioFilePlayerDelegate: AnyObject { | |
func didReceiveAudioSample(_ buffer: AVAudioPCMBuffer, time: AVAudioTime) | |
} | |
class AudioFilePlayer: NSObject { | |
private var audioFile: AVAudioFile? | |
private var audioEngine: AVAudioEngine = AVAudioEngine() | |
private var audioPlayerNode: AVAudioPlayerNode = AVAudioPlayerNode() | |
private var format: AVAudioFormat? | |
weak var delegate: (any AudioFilePlayerDelegate)? | |
override init() { | |
super.init() | |
loadAudioFile() | |
setupAudioEngine() | |
} | |
private func loadAudioFile() { | |
guard let fileURL = Bundle.main.url(forResource: "audio", withExtension: "wav") else { | |
print("Audio file not found in bundle") | |
return | |
} | |
do { | |
let file = try AVAudioFile(forReading: fileURL) | |
self.audioFile = file | |
self.format = file.processingFormat | |
} catch { | |
print("Error loading audio file: \(error)") | |
} | |
} | |
private func setupAudioEngine() { | |
guard let format = self.format else { | |
print("Audio format is nil") | |
return | |
} | |
audioEngine.attach(audioPlayerNode) | |
audioEngine.connect(audioPlayerNode, to: audioEngine.mainMixerNode, format: format) | |
audioPlayerNode.volume = 0 | |
do { | |
try audioEngine.start() | |
} catch { | |
print("Error starting audio engine: \(error)") | |
} | |
} | |
func play() { | |
guard let audioFile = self.audioFile, let format = self.format else { | |
print("Audio file or format is nil") | |
return | |
} | |
audioPlayerNode.scheduleFile(audioFile, at: nil) { | |
print("AudioFilePlayer finished") | |
} | |
audioPlayerNode.installTap(onBus: 0, bufferSize: 1024, format: format) { [weak self] (buffer, time) in | |
self?.delegate?.didReceiveAudioSample(buffer, time: time) | |
} | |
audioPlayerNode.play() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment