精选文章

33. 音视频入门

2019-03-28 · 音频

33. 音视频入门

音视频开发的关键在于:音频会话配置正确、播放链路可控、资源释放及时。

一、音频会话

import AVFoundation

func setupAudioSession() throws {
    let session = AVAudioSession.sharedInstance()
    try session.setCategory(.playback, mode: .default, options: [])
    try session.setActive(true)
}

常用分类:

  • .playback:只播放
  • .playAndRecord:录音 + 播放

二、音频播放(本地)

final class AudioPlayer: NSObject, AVAudioPlayerDelegate {
    private var player: AVAudioPlayer?

    func play(url: URL) throws {
        player = try AVAudioPlayer(contentsOf: url)
        player?.delegate = self
        player?.prepareToPlay()
        player?.play()
    }

    func pause() { player?.pause() }
    func stop() { player?.stop() }
}

三、录音

final class AudioRecorder {
    private var recorder: AVAudioRecorder?

    func requestAndRecord(to url: URL) throws {
        let session = AVAudioSession.sharedInstance()
        try session.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker])
        try session.setActive(true)

        session.requestRecordPermission { granted in
            guard granted else { return }
            let settings: [String: Any] = [
                AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
                AVSampleRateKey: 44100,
                AVNumberOfChannelsKey: 2,
                AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
            ]
            do {
                self.recorder = try AVAudioRecorder(url: url, settings: settings)
                self.recorder?.record()
            } catch {
                print(error)
            }
        }
    }

    func stop() { recorder?.stop() }
}

四、视频播放(AVPlayer)

import AVFoundation

final class VideoView: UIView {
    private let player = AVPlayer()
    private let playerLayer = AVPlayerLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        playerLayer.player = player
        playerLayer.videoGravity = .resizeAspect
        layer.addSublayer(playerLayer)
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    override func layoutSubviews() {
        super.layoutSubviews()
        playerLayer.frame = bounds
    }

    func play(url: URL) {
        player.replaceCurrentItem(with: AVPlayerItem(url: url))
        player.play()
    }
}

五、播放进度监听

final class PlayerObserver {
    private var token: Any?
    private let player: AVPlayer

    init(player: AVPlayer) { self.player = player }

    func start() {
        token = player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 0.5, preferredTimescale: 600), queue: .main) { time in
            let seconds = CMTimeGetSeconds(time)
            print("progress: \(seconds)")
        }
    }

    deinit {
        if let token { player.removeTimeObserver(token) }
    }
}

音视频的稳定性主要靠“会话正确 + 资源释放干净 + 主线程不阻塞”。这三点做到位,体验就稳。

JJ

作者简介

专注于内容创作、产品策略与设计实践。欢迎交流合作。

上一篇 下一篇