AVPlayer

김동현·2022년 9월 10일
0

iOS

목록 보기
9/13


Mellon이나 Apple Music과 같이
audio를 재생시키는 앱은 어떻게 구현되어 있을까 라는 궁금증이 생겼습니다.

iOS 앱에서 audio를 재생시키는 방법은 꽤 많았는데요.
오늘은 그중 하나인 AVPlayer에 대해 소개해볼까 합니다.

먼저 AVPlayer를 알아보기 전에
AVFoundation에 대해 알고 가면 좋을 것 같아서
간단하게 짚고 넘어가 보겠습니다.

AVFounation


Apple의 미디어 Framework인 AVFoundation
지금 설명하려는 audio playback 기능 말고도
많은 미디어 처리 작업을 제공합니다.(video, 카메라, 편집 등)

또한 이 Framework를 사용하여
HTTP Live Streaming을 통해
실시간으로 mp3파일을 재생하고 제어할 수 있다고 합니다.

하지만 AVFoundation은 하단 이미지와 같이
UIKit Framework보다 Low한 level에 위치해 있어
재생과 관련된 UI를 제공해주지 않고 있습니다.
그래서 Apple은 player Interface를 제공할 수 있고,
보다 빠른 player의 기능 구현을 진행할 수 있는
AVKit Framework를 UIKit 상단에 마련해 두었습니다.

그럼 AVKit의 AVPlayerViewController에 대해서 알아볼까요?

AVKit

아래는 AVKit 내부에 있는 AVPlayerViewController를 사용해서
player를 구현하는 방법입니다.

@objc private func didTapButton() {
	var player: AVPlayer?
	let playerController = AVPlayerViewController()
	guard let url = URL(string: "https://......") else {
		return
	}
	player = AVPlayer(url: url)
	playerController.player = player
	playerController.player?.play()
	present(playerController, animated: true, completion: nil)
}


개발자가 직접 UI에 관여하지 않아도
오디오 제어에 대해 접근성이 굉장히 뛰어난걸 확인할 수 있습니다.
하지만 대부분 player를 구현할 때 이런 심플한 모습은 원하지 않았을 것입니다.😂
그렇다면 AVPlayerViewController에서 제공하고 있는 인터페이스를 직접 구현하는 방법은 어떤게 있을까요?

위에서 잠깐 설명 드렸던
보다 low한 level인 AVFoundation Framework의
AVPlayer를 사용하여 audio를 재생시키고,
의도하고자 하는 UI로 player를 커스텀하면 될 것 같은데요!
그럼 AVPlayer에 대해 알아보겠습니다.

AVPlayer


일단 기능구현에 앞서
mp3 URL, button, slider를 준비하고,
그리고 AVPlayer와 AVPlayerItem을 만들도록 하겠습니다.

let player = AVPlayer()
var playerItem: AVPlayerItem?


그리고 stream을 진행할 mp3 URL을 사용하여
AVPlayerItem을 만들고
player의 playerItem으로 할당 해주도록 하겠습니다.

guard let url = URL(string: "https:......") else {
	return
}
playerItem = AVPlayerItem(url: url)
player.replaceCurrentItem(with: playerItem)


다음은 버튼을 터치했을때 Action을 정의 해주도록 하겠습니다.
이제 버튼을 터치했을 때 해당 URL이 가진 음원이 재생되는 걸 확인할 수 수 있을 것입니다.

@objc private func didTapButton() {
    // timeControlStatus에 따른 분기
    if player.timeControlStatus == .paused {
        player.play()
    } else {
        player.pause()
    }
    button.isSelected.toggle()
}


총 재생 시간 표기와 currentTimeLabel, currentTimeSlider의 value set은 아래와 같습니다.🙌

// duration(총 재생 시간)
guard let durationTime = self?.player.currentItem?.duration else { return }
let totalSeconds = Int(CMTimeGetSeconds(durationTime))
let seconds = totalSeconds % 60
let minutes = totalSeconds / 60
let timeFormatString  = String(format: "%02d:%02d", minutes, seconds)
self?.durationLabel.text = timeFormatString

// 미디어의 재생시간의 흐름을 알고 싶거나 현재 재생시간에 따라 인터페이스를 변경하고 싶을 때
// time은 CMTime 타입의 값으로, 입력한 interval 주기를 가진채로 completion으로 나오게 됩니다.
let interval = CMTimeMakeWithSeconds(1, preferredTimescale: Int32(NSEC_PER_SEC)) // 1초
player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self](time) in
    // update currentLabel
    let totalSeconds = Int(CMTimeGetSeconds(time))
    let seconds = totalSeconds % 60
    let minutes = totalSeconds / 60
    let timeFormatString  = String(format: "%02d:%02d", minutes, seconds)
    self?.currentTime.text = timeFormatString

    // update slider
    let currentTimeSeconds = CMTimeGetSeconds(self?.player.currentTime()) // 현재 진행 위치
    let durationSeconds = CMTimeGetSeconds(self?.player.currentItem?.duration ??
                                            CMTimeMake(value: 1, timescale: 1)) // 총 길이
    let percentage = currentTimeSeconds / durationSeconds // 현재 위치 / 총 길이
    self?.songSlider.value = Float(percentage) // set slider value
}
profile
iOS 개발자 김동현입니다 :)

0개의 댓글