1

I'm attempting to load a remote MP3 through the AVAudioPlayer in Swift 4. So far, everything is working just great.

Now, I'm attempting to load our secure URL, which uses Basic Authentication for the URL.

What I have is this:

    let username = "my_username"
    let password = "my_password"
    let loginString = String(format: "%@:%@", username, password)
    let loginData = loginString.data(using: String.Encoding.utf8)!
    let base64LoginString = loginData.base64EncodedString()

    // create the request
    let url = URL(string: "https://audio.my_domain.com/\(hashKey)/my_file.mp3")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")

    guard let audioPlayer = try? AVAudioPlayer(contentsOf: request) else {
        self.endPlayback()
        return
    }

Of course the error that I get is:

Cannot convert value of type 'URLRequest' to expected argument type 'URL'

I'm not surprised by this as a URL is not a URLRequest object. So, my question is. How can I load the URL stream into the AVAudioPlayer using Basic HTTP Authentication?

I can't seem to find anywhere that does this. Perhaps this isn't possible?

CodeLikeBeaker
  • 20,682
  • 14
  • 79
  • 108

1 Answers1

2

First of all, AVAudioPlayer is not meant to play audio over the network:

Use this class for audio playback unless you are playing audio captured from a network stream or require very low I/O latency.

You'll want to either download the complete mp3 file into either a local file or a Data object before playing, or use an AVPlayer instead (which is designed to be able to play audio over the network).

In order to create an AVPlayer, that plays audio over the network must first create an AVURLAsset:

let asset = AVURLAsset(url: URL(string: "https://example.com/file.mp3")!)

There are at least two ways to use basic authentication with an AVURLAsset:

  1. Use the AVURLAssetHTTPHeaderFieldsKey to set a custom header. Note that this key is undocumented.

  2. Add the credential to the shared URLCredentialStorage:

    let credential = URLCredential(
        user: "username",
        password: "password", 
        persistence: .forSession
    )
    let protectionSpace = URLProtectionSpace(
        host: "example.com",
        port: 443,
        protocol: "https",
        realm: nil,
        authenticationMethod: NSURLAuthenticationMethodHTTPBasic
    )
    URLCredentialStorage.shared.setDefaultCredential(credential, for: protectionSpace)
    

You can then create an AVPlayerItem with your asset, and finally an AVPlayer:

let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
NobodyNada
  • 7,529
  • 6
  • 44
  • 51