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
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