Swiftui Firebase NowPlayable Audio AVPlayerItem.无法将类型为"存储引用"的值转换为预期的参数类型"URL"



我似乎不知道如何通过firebase使我的流媒体音频成为Xcode 12中的一个现在可以使用SwiftUI播放的应用程序。这是我的密码。我向苹果公司寻求帮助,他们给了我一个应用程序内部保存的m4a音频样本。我正在使用Firebase来实时播放音频、翻唱艺术、接收歌曲标题和艺术家信息。我只是想知道如何用最少的代码让它现在可以播放。该代码适用于存储在应用程序中的url和音频,但不能通过Firebase进行流式传输。所有的信息、音频和艺术都上传到Firebase中并实时显示,这样我就可以立即上传新音乐,而无需在应用商店更新应用程序。我只知道如何在SwiftUI中编码。

import AVFoundation
import MediaPlayer
import Firebase
// Static metadata about each song.
struct Album: Identifiable, Codable, Equatable, Hashable {
var id = UUID()
var name : String
var image: String
var artist: String
var songs : [Song]
enum CodingKeys: String, CodingKey {
case name
case image
case artist
case songs
}
}
struct Song: Identifiable, Codable, Equatable, Hashable {
var id = UUID()
var name : String
var image: String
var artist: String
var time: String
var file: String
enum CodingKeys: String, CodingKey {
case name
case image
case artist
case time
case file
}
}
struct datatype: Identifiable, Equatable, Hashable {
var id : String
var image : String
}
struct DynamicMetadata {
var playerState: PlayerState
var playerRate: Float
var totalTime: Float
var elapsedTime: Float
}
// Possible values of the `playerState` property.
enum PlayerState {
case stopped
case playing
case paused
}
class AudioPlayer: ObservableObject {

// MARK: Playback Machinery

// The songs being played.

private var songItems: [Song]

// The player used to play individual songs.
private var player: AVPlayer!

// Index of the currently playing item.
private var currentItemIndex = 0

// The currently playing item.
@Published private(set) var currentStaticMetadata: Song?

// The current logical state of the player.
private(set) var playerState: PlayerState = .stopped

// The current playback state.
@Published private(set) var currentDynamicMetadata: DynamicMetadata?

// `true` if the current session has been interrupted by another app.
private var isInterrupted: Bool = false

// Observers of notifications and property changes.
private var itemObserver: NSKeyValueObservation!
private var rateObserver: NSKeyValueObservation!
private var statusObserver: NSObjectProtocol!
private var interruptionObserver: NSObjectProtocol!
private var timeObserver: Any!

init(metadata: [Song]) {
songItems = metadata
}

// MARK: State Changes

// Update Now Playing Info when the current item changes.
private func handlePlayerItemChange() {
guard playerState != .stopped else { return }

// Set the Now Playing Info from static item metadata.
let songItem = songItems[currentItemIndex]
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
var nowPlayingInfo = [String: Any]()

nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = MPNowPlayingInfoMediaType.audio.rawValue
nowPlayingInfo[MPMediaItemPropertyTitle] = songItem.name
nowPlayingInfo[MPMediaItemPropertyArtist] = songItem.artist
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = songItem.name

nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo

// And set it for the UI too.
currentStaticMetadata = songItem
}

// Update Now Playing Info when playback rate or position changes.
private func handlePlaybackChange() {
guard playerState != .stopped else { return }

// Find the current item.

guard let currentItem = player.currentItem else { stop(); return }
guard currentItem.status == .readyToPlay else { return }

// Set the Now Playing Info from dynamic metadata.
let playbackInfo = DynamicMetadata(playerState: playerState, playerRate: player.rate, totalTime: Float(currentItem.duration.seconds), elapsedTime: Float(currentItem.currentTime().seconds))
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]()

nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = playbackInfo.totalTime
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = playbackInfo.elapsedTime
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = playbackInfo.playerRate
nowPlayingInfo[MPNowPlayingInfoPropertyDefaultPlaybackRate] = 1.0

nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo

// And set it in the UI too.
currentDynamicMetadata = playbackInfo
}

// Handle an audio session interruption notification.
private func handleAudioSessionInterruption(notification: Notification) {

// Retrieve the interruption type from the notification.

guard let userInfo = notification.userInfo,
let interruptionTypeUInt = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
let interruptionType = AVAudioSession.InterruptionType(rawValue: interruptionTypeUInt) else { return }

// Begin or end an interruption.
switch interruptionType {

case .began:
isInterrupted = true
case .ended:

// When an interruption ends, determine whether playback should resume
// automatically, and reactivate the audio session if necessary.

do {
try AVAudioSession.sharedInstance().setActive(true)

isInterrupted = false
var shouldResume = false
if let optionsUInt = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt,
AVAudioSession.InterruptionOptions(rawValue: optionsUInt).contains(.shouldResume) {
shouldResume = true
}

switch playerState {
case .stopped:
break

case .playing where shouldResume:
player.play()

case .playing:
playerState = .paused

case .paused:
break
}
}

// When the audio session cannot be resumed after an interruption,
// invoke the handler with error information.

catch {
print(error.localizedDescription)
}

@unknown default:
break
}
}

// MARK: Utilities

private func playerItem(atIndex itemIndex: Int) -> AVPlayerItem {
let songItem = songItems[itemIndex]
let songURL = Storage.storage().reference(forURL: songItem.file)
songURL.downloadURL { (url, error) in
if error != nil {
print("error")
} else {

do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default)
//                    try AVAudioSession.sharedInstance().setActive(true)
}
catch {
// report for an error
}
//                var player = AVPlayer(url: url!)
self.player = AVPlayer(url: url!) //
//                data.player = try! AVAudioPlayer(contentsOf: URL(fileURLWithPath: url!))
//                data.player = try! AVAudioPlayer(contentsOf: url!)
self.player.play()
//                self.isPlaying = true
//                self.showcontrols = true
//                audioPlayer.playPauseTrack()
}
}
return AVPlayerItem(url: songURL)
}

我猜错误来自这里:

return AVPlayerItem(url: songURL)

您已经将songURL声明为let songURL = Storage.storage().reference(forURL: songItem.file),这意味着它是StorageReference,而AVPlayerItem无法处理它。

问题是您无法在那里返回有效的内容,因为下载URL尚未加载。我不确定AVPlayerItem做什么,但您可能想看看是否可以稍后在回调中构建它,在回调中您已经做了self.player = AVPlayer(url: url!)

最新更新