Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- map
- Observable
- 클린 코드
- 리펙토링
- MVVM
- 리펙터링
- Clean Code
- 리팩토링
- ribs
- Refactoring
- 애니메이션
- Xcode
- RxCocoa
- clean architecture
- swift documentation
- ios
- 스위프트
- swiftUI
- HIG
- uiscrollview
- rxswift
- Protocol
- collectionview
- combine
- Human interface guide
- UICollectionView
- tableView
- uitableview
- SWIFT
- UITextView
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 1. 오디오 처리 - AVPlayer, AVAudioPlayer 개념 본문
1. 오디오 처리 - AVPlayer, AVAudioPlayer 개념 (실시간 스트리밍, 로컬 파일 재생)
2. 오디오 처리 - AVAudioRecoder 개념 (녹음)
비교
- 실시간 스트리밍 -> AVPlayer 사용
- 로컬 파일 재생 -> AVAudioPlayer 사용
- 음성 특수 효과 or 변조 -> AVAudioEngine 사용
cf) 녹음 -> AVAudioRecoder 사용
비동기 처리의 편의를 위해서 사용한 프레임워크
pod 'RxSwift'
pod 'RxCocoa'
pod 'RxAVFoundation'
커스텀 Rx extension
- 버튼 하나로 토글 처리하는데 편리한 isHighlighted, isSelected 추가
// Rx+Extension.swift
extension Reactive where Base: UIControl {
public var isHighlighted: Observable<Bool> {
self.base.rx.methodInvoked(#selector(setter: self.base.isHighlighted))
.compactMap { $0.first as? Bool }
.startWith(self.base.isHighlighted)
.distinctUntilChanged()
.share()
}
public var isSelected: Observable<Bool> {
self.base.rx.methodInvoked(#selector(setter: self.base.isSelected))
.compactMap { $0.first as? Bool }
.startWith(self.base.isSelected)
.distinctUntilChanged()
.share()
}
}
예제로 사용할 mp3 준비
- 서버로부터 mp3의 url을 받아서 스트리밍 하고 싶은 경우 사용
- 예제로 사용할 mp3 url 준비
// 출처: https://www.soundhelix.com/audio-examples
https://www.soundhelix.com/examples/mp3/SoundHelix-Song-6.mp3
- mp3파일을 다운받아서 Xcode에 이동
AVPlayer 사용 방법
- 실시간 스트리밍에 사용되므로, mp3 url이 있으면 그 값을 가지고 플레이가 가능
- AVPlayer는 AVPlayerItem이라는 것을 가지고 있고, AVPlayer가 이 item을 변경해가면서 url을 바꾸어서 사용
self.player.replaceCurrentItem(with: self.item)
- item에 접근하여 오디오 파일의 전체 시간과 경과 시간을 획득
item.rx.status
.filter { $0 == .readyToPlay }
.observe(on: MainScheduler.asyncInstance)
.map { _ in item.asset.duration.seconds }
.bind { print("전체 시간 = \($0)") }
.disposed(by: self.itemDisposeBag)
self.player.rx
.periodicTimeObserver(interval: .init(seconds: 0.5, preferredTimescale: Int32(NSEC_PER_SEC)))
.map(\.seconds)
.bind { print("경과 시간 = \($0)") }
.disposed(by: self.disposeBag)
- Player는 최초에 한 번 초기화 해놓고, url이 변경될때 이 값을가지고 item을 만들어서 player의 item을 변경해주는 방식으로 사용
// MyPlayerView.swift
private let player = AVPlayer()
var url: URL? {
didSet {
guard let url = self.url else { return self.player.replaceCurrentItem(with: nil) }
let item = AVPlayerItem(url: url)
item.rx.status
.filter { $0 == .readyToPlay }
.observe(on: MainScheduler.asyncInstance)
.map { _ in item.asset.duration.seconds }
.bind { print("전체 시간 = \($0)") }
.disposed(by: self.itemDisposeBag)
self.player.rx
.periodicTimeObserver(interval: .init(seconds: 0.5, preferredTimescale: Int32(NSEC_PER_SEC)))
.map(\.seconds)
.bind { print("경과 시간 = \($0)") }
.disposed(by: self.disposeBag)
self.player.replaceCurrentItem(with: item)
}
}
- play, stop 메소드
// MyPlayerView.swift
func play() {
self.player.play()
}
func stop() {
self.player.pause()
self.player.seek(to: .zero)
}
- 사용하는쪽
// ViewController.swift
private let playerView = MyPlayerView()
...
let url = URL(string: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-6.mp3")!
self.playerView.url = url
AVAudioPlayer 사용 방법
- AVAudioPlayer는 로컬에 있는 mp3파일과 같은 것을 재생시키기 위함
- 스트리밍 재생은 불가
- AVPlayer와는 다르게 item을 변경해주면서 쓰지 않고, AVAudioPlayer 객체에 url을 넣어서 새로 생성하여 사용
- delegate로 오류가났는지, 끝났는지 체크
// MyAudioPlayerView.swift
private var audioPlayer: AVAudioPlayer? {
didSet {
self.audioPlayer?.delegate = self
self.audioPlayer?.prepareToPlay()
}
}
extension MyAudioPlayerView: AVAudioPlayerDelegate {
func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
guard let error = error else { return }
print("occured error = \(error)")
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("did finish playing")
}
}
- play할때 url을 가지고 AVAudioPlayer인스턴스를 생성하여, 재생
// MyAudioPlayerView.swift
func play() {
guard let url = url else { return }
self.audioPlayer = try? AVAudioPlayer(contentsOf: url)
Observable<Int>
.interval(.milliseconds(500), scheduler: MainScheduler.asyncInstance)
.compactMap { [weak self] _ in self?.audioPlayer?.currentTime }
.bind { print("경과 시간 = \($0)") }
.disposed(by: self.playDisposeBag)
self.audioPlayer?.play()
}
- stop() 메소드
// MyAudioPlayerView.swift
private func stop() {
self.audioPlayer?.pause()
self.playerDisposeBag = DisposeBag()
}
* 전체 코드: https://github.com/JK0369/ExAudioPlayer
* 참고
https://github.com/pmick/RxAVFoundation
https://loganberry.tistory.com/20
https://larztech.com/posts/2020/05/effects-avaudioengine/
'iOS 응용 (swift)' 카테고리의 다른 글
Comments