Why AVPlayer downloading first instead live streaming?

前端 未结 1 1952
有刺的猬
有刺的猬 2021-02-14 01:13

First time I am working with AVPlayer and I want to play a mp3 file using HTTP request with live streaming. I use AVPlayer that is working fine to play mp3 files, b

1条回答
  •  甜味超标
    2021-02-14 01:46

    Edit for in addition: Also Luaan is right. "Live streaming needs server support - at least the ability to do partial downloads. Does some other player allow live streaming with that URL?" You should also try with an undefined duration sound url.

    Have you tried to approach like it is an undefined duration audio stream ?

      avplayerItem = CachingPlayerItem(url: url, recordingName: recordingName ?? "default.mp3")
    

    CachingPlayerItem going to prepare an AVURLAsset from the url.

     init(url: URL, customFileExtension: String?, recordingName: String) {
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
        let scheme = components.scheme,
        var urlWithCustomScheme = url.withScheme(cachingPlayerItemScheme) else {
        fatalError("Urls without a scheme are not supported")
        }
        self.recordingName = recordingName
        self.url = url
        self.initialScheme = scheme
        if let ext = customFileExtension {
        urlWithCustomScheme.deletePathExtension()
        urlWithCustomScheme.appendPathExtension(ext)
        self.customFileExtension = ext
        }
        let asset = AVURLAsset(url: urlWithCustomScheme)
        asset.resourceLoader.setDelegate(resourceLoaderDelegate, queue: DispatchQueue.main)
        super.init(asset: asset, automaticallyLoadedAssetKeys: nil)
        resourceLoaderDelegate.owner = self
        addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(playbackStalledHandler), name:NSNotification.Name.AVPlayerItemPlaybackStalled, object: self)
        }
    

    After AVPlayerItem is initialized, make an AVPlayer object from it so that it can kick start the process of loading audio stream from the given url:

    player = AVPlayer(playerItem: playerItem)
    player.automaticallyWaitsToMinimizeStalling = false
    
    func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
    if playingFromData {
    // Nothing to load.
    } else if session == nil {
    // If we're playing from a url, we need to download the file.
    // We start loading the file on first request only.
    guard let initialUrl = owner?.url else {
    fatalError("internal inconsistency")
    }
    startDataRequest(with: initialUrl)
    }
    pendingRequests.insert(loadingRequest)
    processPendingRequests()
    return true
    }
    

    Once resource is installed:

    func startDataRequest(with url: URL) {
    var recordingName = "default.mp3"
    if let recording = owner?.recordingName{
    recordingName = recording
    }
    fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
    .appendingPathComponent(recordingName)
    let configuration = URLSessionConfiguration.default
    configuration.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData
    session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    session?.dataTask(with: url).resume()
    outputStream = OutputStream(url: fileURL, append: true)
    outputStream?.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
    outputStream?.open()
    }
    

    Then, start receiving data bytes into the delegate function:

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
    

    Now you have started receiving live audio stream.

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
    let bytesWritten = data.withUnsafeBytes{outputStream?.write($0, maxLength: data.count)}
    print("bytes written :\(bytesWritten!) to \(fileURL)")
    }
    

    Now create an OutputStream object, open it then append the bytes we are receiving in the above delegate function and thats it, we saved the desired part of the live audio stream.

    Taken from: Medium Article, Mohan Pandey

    0 讨论(0)
提交回复
热议问题