DEV Community

Jyotish Biswas
Jyotish Biswas

Posted on

Need Help Playing m3u8 Link in AVPlayer with AVAssetResourceLoaderDelegate

Question:

I'm trying to secure my m3u8 streaming link with a token. To achieve this, I'm using AVAssetResourceLoaderDelegate in my SwiftUI app. However, the video doesn't play in AVPlayer when I'm using the AVAssetResourceLoaderDelegate. I can see that data is being received in the resourceLoader, but the player does not start playback.

Here's the code I'm using:

`struct VVideoPlayerView: View {
@State private var player: AVPlayer?
@EnvironmentObject var pilot: UIPilot
var body: some View {
VStack {
VerticalSpacer(height: 50)
HStack {
Image(systemName: "arrow.left")
.onTapGesture {
pilot.pop()
}
Spacer()
Text("liveStreamData.titleShort")
.font(.poppins(.semibold, size: 18))
.lineLimit(1)
HorizontalSpacer(width: 16)
Spacer()
}
.padding(.horizontal)
if let player = player {
VideoPlayer(player: player)
.onAppear {
player.play()
}
.onDisappear {
player.pause()
}
} else {
Text("Loading video...")
}
}
.onAppear {
setupPlayer()
}
}

private func setupPlayer() {
    guard let url = URL(string: "https://assets.afcdn.com/video49/20210722/v_645516.m3u8") else {
        print("Invalid URL")
        return
    }
    // Replace the scheme with a custom scheme
    var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
    components?.scheme = "customscheme" // Change the scheme to a custom one
    guard let customURL = components?.url else {
        print("Failed to create custom URL")
        return
    }
    let asset = AVURLAsset(url: customURL)
    // Set the resource loader delegate
    let resourceLoaderDelegate = VideoResourceLoaderDelegate()
    asset.resourceLoader.setDelegate(resourceLoaderDelegate, queue: DispatchQueue.main)
    let playerItem = AVPlayerItem(asset: asset)
    player = AVPlayer(playerItem: playerItem)
}
Enter fullscreen mode Exit fullscreen mode

}

class VideoResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate {
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
guard let url = loadingRequest.request.url else {
print("Invalid request URL")
return false
}
// Replace the custom scheme with the original HTTP/HTTPS scheme
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
components?.scheme = "https" // Change the scheme back to HTTP/HTTPS
guard let originalURL = components?.url else {
print("Failed to convert URL back to HTTPS")
return false
}
// Fetch the data from the original URL
let urlSession = URLSession.shared
let task = urlSession.dataTask(with: originalURL) { data, response, error in
if let error = error {
print("Error loading resource: (error)")
loadingRequest.finishLoading(with: error)
return
}
if let data = data, let dataRequest = loadingRequest.dataRequest {
print("Data loaded: (data.count) bytes")
dataRequest.respond(with: data)
loadingRequest.finishLoading()
} else {
print("No data received")
loadingRequest.finishLoading(with: NSError(domain: "VideoResourceLoader", code: -1, userInfo: nil))
}
}
task.resume()
return true
}

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, didCancel loadingRequest: AVAssetResourceLoadingRequest) {
    print("Loading request was canceled")
}
Enter fullscreen mode Exit fullscreen mode

}
`

Problem:

The video does not play when using AVAssetResourceLoaderDelegate. The data is being loaded correctly as confirmed by the logs, but AVPlayer fails to start playback.
Without the resource loader, the video plays without any issues.
Question:

What could be causing the player to not play the video when using AVAssetResourceLoaderDelegate?
Are there any additional steps or configurations I need to ensure smooth playback while using a resource loader?
Any help would be greatly appreciated!

Top comments (0)