3
votes

I am using AVPlayer to play an mp3 audio file only. I am using a url that I tested and works fine. I needed to use the AVPlayer because I needed to setup a UISlider programmatically and AVPlayer is convenient. The UISlider works and updates as the audio plays. The audio might be be playing but I cannot hear the sound. I say this because the UISlider is working.

Update: You can hear the audio when building the app on a simulator. Issue occurs when building it on device - mine is XS MAX.

Link to screen recordong -> Visit: https://streamable.com/nkbn8

I have tried using the same URL with AVAudioPlayer and audio plays and you can hear it.

private func setupAudioContent() {

    let urlString = "https://s3.amazonaws.com/kargopolov/kukushka.mp3"
    if let url = NSURL(string: urlString) {
        audioPlayer = AVPlayer(url: url as URL)

        let playerLayer = AVPlayerLayer(player: audioPlayer)
        self.layer.addSublayer(playerLayer)
        playerLayer.frame = self.frame

        audioPlayer?.play()
        audioPlayer?.volume = 1.0
        audioPlayer?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)

        let interval = CMTime(value: 1, timescale: 2)
        audioPlayer?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { (progressTime) in

            let currentTime = CMTimeGetSeconds(progressTime)
            let currentTimeSecondsString = String(format: "%02d", Int(currentTime.truncatingRemainder(dividingBy: 60)))
            let currentTimeMinutesString = String(format: "%02d", Int(currentTime / 60))
            self.currentTimeLabel.text = "\(currentTimeMinutesString):\(currentTimeSecondsString)"

            if let duration = self.audioPlayer?.currentItem?.duration {
                let durationsSeconds = CMTimeGetSeconds(duration)

                self.audioSlider.value = Float(currentTime / durationsSeconds)
            }
        })
    }
}


override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "currentItem.loadedTimeRanges" {
        isAudioPlaying = true

        if let duration = audioPlayer?.currentItem?.duration {
            let seconds = CMTimeGetSeconds(duration)
            let secondsText = Int(seconds) % 60
            let minutesText = String(format: "%02d", Int(seconds) / 60)
            audioLengthLabel.text = "\(minutesText):\(secondsText)"
        }
    }
}


@objc func handleSliderChange() {
    if let duration = audioPlayer?.currentItem?.duration {
        let totalSeconds = CMTimeGetSeconds(duration)
        let value = Float64(audioSlider.value) * totalSeconds
        let seekTime = CMTime(value: Int64(value), timescale: 1)
        audioPlayer?.seek(to: seekTime, completionHandler: { (completedSeek) in
        })
    }
}

Expected result: Hear Audio playing

Actual result: cannot hear audio playing. Seems like audio is playing just no sound.

2

2 Answers

11
votes

When using AVPlayer you should make sure your device is not on silent mode as that will cause to not output audio even though your volume is at max.

If you would like to keep your device on silent mode and still play the audio you can use the following code before your .play():

do {
            try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
        }
        catch {
            // report for an error
            print(error)
        }
2
votes

I try with a simpliest version and it works on the simulator and the device (XS).

as @N.Der mentionned, check the category mode. in this situation, in silent mode, no audio is heard.

import AVFoundation
import UIKit

final class ViewController: UIViewController {
    private var audioPlayer: AVPlayer?

    override func viewDidLoad() {
        super.viewDidLoad()

        setupAudioContent()
    }

    private func setupAudioContent() {
        guard let url = URL(string: "https://s3.amazonaws.com/kargopolov/kukushka.mp3")
            else { return }

        audioPlayer = AVPlayer(url: url as URL)
        audioPlayer?.play()
    }
}

To manage easily avplayer configurations and all interruptions, you can try this library: MordernAVPlayer