기타/iOS 기초

[iOS Swift AVFoundation] 2편. 음성파일 재생 하기 - AVPlayer

studying develop 2022. 7. 15. 02:26

[iOS Swift AVFoundation] 1편. 미디어 파일을 다루려면? - AVKit

[iOS Swift AVFoundation] 2편. 음성파일 재생 하기 - AVPlayer

 

일단 기본적으로 음성 재생으로 시작해보자.

 


키워드

AVPlayer

AVFoundation

replaceCurrentItem

AVAsset

AVPlayerItem

General State Observations

Timed State Observations

AVKit

AVPlayerLayer


 

AVPlayer

An object that provides the interface to control the player’s transport behavior.

미디어 파일에 대한 컨트롤러인셈이다.

 

개요

플레이어를 통해 미디어 에셋을 재생하고, 원하는 타이밍에 재생할 수 있다. 로컬에 저장된 음성, 동영상 파일뿐 아니라 원격 HTTP Live 스트리밍도 가능하게 해준다.

 

플레이어는 단일 미디어 에셋만 사용하는게 좋다. 우리가 플레이어 인스턴스를 재사용할 수 있는데, replaceCurrentItem을 사용하여 재생중인 미디어 에셋을 교체해주면됨, 그리고 미디어 에셋의 실행 순서에 관해서는 AVQueuePlayer를 통해 큐를 관리하면 된다.

 

AVPlayer는 미디어 에셋을 재생하는 역할이고, AVFoundation에 있는 AVAsset class를 통해 정적인 미디어들을 모델링할 수 있다함, 예를 들면 재생 시간, 생성 날짜 그리고 등등? 그리고 그 자체?, 하지만 이걸로는 영상을 플레이어를 통해 재생할 수 없다는듯.

그래서 어쨋든, 재생하기 위해서는, 동적인 역할을 하는 AVPlayerItem을 생성해야 한다 함.

 

대충 해석해보자면, 파일을 에셋 형태로 저장은 하는데, 이걸 재생하려면 플레이어 아이템 형태로 바꿔줘야 한다는듯.

 

AVPlayer는 동적인 객체로 상태를 갖고, 그 상태가 계속 변한다함. 재생기의 상태를 관찰할 수 있는 방법이 두개라는데,

 

1. General State Observations

이건 , KVO(키발류 관찰)을 통해 많은 플레이어들의 동적인 프로퍼티들을 관찰하는 것이다, 예를 들면 currentItem 또는 재생 속도등?

2. Timed State Observations

KVO는 지속적으로 변화하는 상태를 관찰하는데는 적합하지 못하다, 예를 들면 플레이어의 시간등을. AVPlayer는 두가지 메소드를 제공한다 시간 변화를 관찰하기 위해서.

아래 두개의 메소드를 통해, 주기적으로 또는 경계적으로(경계선) 관찰을 도와준다, 변화가 발생하면, 콜백 블록 또는 클로저를 이러한 메소드에 제공하여 대응하도록 해준다, 예를 들면 ui를.


AVPlayer와 AVPlayerItem는 시각적인 객체들은 아니다, 이것만으로는 화면에 표현을 할 수 없다느 말임. 

이제 우리가 화면에 미디어 에셋과 관련된걸 표현하기 위해서는 AVKit 또는 AVPlayerLayer를 알아야 한다.

 

AVKit

비디오 컨텐츠를 표현하는 가장 최고의 방법은, 이 프레임워크에 있는 AVPlayerViewController  클래스를 사용하는거다. 이 클래스를 사용하면 비디오 콘텐츠를 표현하고 재생을 조절하고 다른 미디어들도 표현 가능한듯.

 

AVPlayerLayer

커스텀 사용자 인터페이스를 만들려면, 이 레이어를 사용해라. 이 레이어를 뷰들의 지원 레이어 또는 레이어 계층에 직접 추가가 가능하다.  AVPlayerViewController와는 달리, 이 레이어는 재생에 대한 컨트롤을 제공하지는 않는다. 오직 시각적으로 콘텐츠를 보여주기만 함. 재생 조절 기능은 (재생, 중지, 이동) 개발자의 몫이다...

 

AVSynchronizedLayer를 통해 애니메이션이나 비디오 이동등을 표현할 수 있다는데, 뭔지 잘 모르겠음. 비디오 재생 뷰의 이동같은걸 말하는듯? 동기화 시킬수 있다는거 보니까... 

 


여기에는 AVKit을 사용한 코드를 찾아보자.


내가 검색해서 구현해본 코드, AVFoundation을 사용해서, ui는 없다....

import Foundation
import AVFoundation

class AudioPlayer: ObservableObject {
    var player: AVAudioPlayer?
    
    func playSound() {        
        do {
            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
            try AVAudioSession.sharedInstance().setActive(true)

            /* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
            player = try AVAudioPlayer(contentsOf: getAudioURL())
            
            /* iOS 10 and earlier require the following line:
             player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) */
            
            guard let player = player else {
                return
            }
            
            
            player.play()
            
        } catch let error {
            print(error.localizedDescription)
        }
    }
    
    func getDocumentsDirectory() -> URL {
        print("getDocumentsDirectory() called")
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let docDirectory = paths[0]
        return docDirectory
    }
    
    func getAudioURL() -> URL {
        print("getAudioURL() called")
        return getDocumentsDirectory().appendingPathComponent("audio.m4a")
    }
}

 

 

위 코드가, 내 프로젝트에서 문제가 있었는데, 기존에 AVRecorder를 다른 코드를 보고 따라했는데, 거기서도 

            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
            try AVAudioSession.sharedInstance().setActive(true)

이 두개가 중복되어 문제가 발생한듯. 주석처리하니까 괜찬더라.

 


let playerItem = AVPlayerItem(url: url)
player.replaceCurrentItem(with: playerItem)
player.play()

그리고 이런식으로 AVPlayerItem을 사용할수도 있다.