我似乎不知道如何通过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!)
。