22

I tried to buffer and immediately play remote url audio with swift language.

but problem is with long time to readyToPlay case and play.

for example a sound url takes about 12 to 15 second to run.

this is my code :

var asset: AVAsset!
var player: AVPlayer!
var playerItem: AVPlayerItem!

private var playerItemContext = 0

let requiredAssetKeys = [ "playable","hasProtectedContent"]

let url = URL(string: "http://sound_link.mp3")!
asset = AVAsset(url: url)

playerItem = AVPlayerItem(asset: asset,
                              automaticallyLoadedAssetKeys: requiredAssetKeys)
playerItem.addObserver(self,
                       forKeyPath: #keyPath(AVPlayerItem.status),
                       options: [.old, .new],
                       context: &playerItemContext)

player = AVPlayer(playerItem: playerItem)

that according to this (ExploringAVFoundation) documentation've done that

and for handle that player is ready to player to play i use observeValue func :

override func observeValue(forKeyPath keyPath: String?,of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

   guard context == &playerItemContext else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        return
    }

    if keyPath == #keyPath(AVPlayerItem.status) {
        let status: AVPlayerItemStatus
        if let statusNumber = change?[.newKey] as? NSNumber {
            status = AVPlayerItemStatus(rawValue: statusNumber.intValue)!
        } else {
            status = .unknown
        }
        // Switch over status value
        switch status {
        case .readyToPlay:
            print("readyToPlay \(status.rawValue)")
            player.play() // here play remote sound
        case .failed:
            print("readyToPlay \(status.rawValue)")
        case .unknown:
            print("failed \(status.rawValue)")
        }

    }
}

and this is returned log :

2017-02-08 13:44:00.626036 [15144:3747850] [aqme] 255: AQDefaultDevice (1): skipping input stream 0 0 0x0
readyToPlay 1
2017-02-08 13:44:02.631182 [15144:3747850] [aqme] 255: AQDefaultDevice (173): skipping input stream 0 0 0x0

in above log , take 4 sec to appear readyToPlay 1 then take 10 sec to play sound

sever speed is good and i tried to play server sound in Android and max time to buffer and play sound is about 3 sec.(in Android application) but in IOS buffering and play sound totally , totally take about 15 sec!

Thanks for your attention

Saeid
  • 2,261
  • 4
  • 27
  • 59
  • Is your issue that it takes too long for iOS to download enough of the file to make it playable? Can you post a link to the file that you're testing with so we can do some comparisons? – Dave Weston Feb 12 '17 at 03:54
  • @DaveWeston , No matter with which links - i tried several link - too , links work correctly in `Android` but not in `IOS` – Saeid Feb 12 '17 at 07:29
  • The reason I ask is because in my tests, the sound starts playing nearly instantly. I took the code from your question, and used this URL: http://www.mfiles.co.uk/mp3-downloads/frederic-chopin-piano-sonata-2-op35-3-funeral-march.mp3 – Dave Weston Feb 12 '17 at 13:40
  • @DaveWeston and average waiting second to buffer and play sound? – Saeid Feb 12 '17 at 14:14
  • Less than a second. If you use the same URL as I did, do you still see the slowness? – Dave Weston Feb 12 '17 at 14:18
  • @DaveWeston let me try this url – Saeid Feb 12 '17 at 14:27
  • @DaveWeston - u tried above link - this late 25 sec! – Saeid Feb 14 '17 at 07:13
  • I have also tried and it takes less than 1 second, make sure that you're running the code form the Main thread – DiegoQ Feb 15 '17 at 15:53
  • any updates here? have you solved this problem? – Vladyslav Zavalykhatko Mar 06 '17 at 11:32
  • 1
    @VladHatko not yet - i tried many ways but not resolved - I hope and try that this problem be solved - if solve problem certainly update this page – Saeid Mar 06 '17 at 12:53
  • In my case it takes more than 2minutes.! can anyone tell me how to decrease wait of stalling? I can not use player.automaticallyWaitsToMinimizeStalling = false because due to this player stops again and again, and user have to play this manually. – Muhammad Danish Qureshi Mar 09 '22 at 15:29

2 Answers2

19

Try to use this:

player.automaticallyWaitsToMinimizeStalling = false
Vladyslav Zavalykhatko
  • 15,202
  • 8
  • 65
  • 100
  • according https://developer.apple.com/reference/avfoundation/avplayer/1643482-automaticallywaitstominimizestal , this feature is available iOS 10.0 not lower version – Saeid Mar 07 '17 at 07:18
  • @Saeid, yes it is, but, as I understand, for prior versions it works as if this property was false; in iOS 10 it is true by default. it resolved my issue – Vladyslav Zavalykhatko Mar 07 '17 at 07:32
  • It can not be used - Because it requires conditions and Handel IOS version – Saeid Mar 07 '17 at 07:45
  • 2
    I was struggling really hard with playing the avpalyerItem. and you my friend is a life saver.. – user578386 Mar 29 '17 at 09:28
8

Try to instantiate your avPlayerItem with URL and then fetch other assets in global thread , I think the problems happens because avPlayer is trying to fetch assets in main UI thread I had the same problem when I was trying to read subtitle options from avAssets it took 5-6 seconds more to load the movie in my player.

This is how I solved my problem (in Swift 2), I hope it helps:

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
            let avMediaSelectionGroup : AVMediaSelectionGroup? = self.container.player.currentItem?.asset.mediaSelectionGroupForMediaCharacteristic(AVMediaCharacteristicLegible)
            dispatch_async(dispatch_get_main_queue(), {

                if  (avMediaSelectionGroup != nil && (avMediaSelectionGroup!.options.count != 0) && avMediaSelectionGroup?.options[0].valueForKey("title") != nil)
                {
                  // show hide subtitle button
                }

            })

        })
MohyG
  • 1,335
  • 13
  • 25
  • i tried to put second section of questions's code inside DispatchQueue.global(qos: .userInitiated).async {code} , readyToPlay is ready faster but for play sound it takes many seconds yet! – Saeid Feb 18 '17 at 10:05