gpt4 book ai didi

ios - 获取任何 AudioPlayer 来传输或播放音乐

转载 作者:行者123 更新时间:2023-11-29 01:23:28 32 4
gpt4 key购买 nike

这里有点不知所措。我正在使用 Xcode 7 和 Swift 2,我正在尝试寻找实际有效的流式音频示例。

本质上我希望能够流式传输,但我也试过这个:Swift Radio Streaming AVPlayer

它使用 AVAudioPlayer。 github 代码有效,但是使用相同的音频文件将代码复制到我的项目中会使应用程序崩溃:由于未捕获的异常 'NSInvalidArgumentException',原因:'-[SwiftBasicMVC_Git.AudioStreamProxy copyWithZone:]:无法识别的选择器发送到实例 0x14fdea100'

我还尝试了一些 ACPlayer 示例和 AVQueuePlayer,但没有成功播放任何音乐。

最佳答案

我将单例用于我的基本 radio 应用程序,因为需要在每个页面上访问和处理它。创建起来非常简单,让我们从声明单例和变量开始吧。我会一步一步解释一切;

import AVKit
import AVFoundation

private var radioContext: UInt8 = 1

final class RadioModel: NSObject {

dynamic var radioItem:AVPlayerItem? = nil
dynamic var radioPlayer:AVPlayer? = nil
static let sharedModel = RadioModel()
private final let dataModel = BasicRadioApp.DataManager

private override init() {
super.init()

do {
_ = try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
_ = try AVAudioSession.sharedInstance().setActive(true)
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
} catch {
print("Error")
}
}

如果您想将 AirPlay 模式用于播客或广播,您必须使用 KVO(键值观察器)控制您的声音对象,它不支持 Swift。因此,我们的 AVPlayerItemAVPlayer 对象由 dynamic 定义,这意味着根据文档;

Apply this modifier to any member of a class that can be represented by Objective-C. When you mark a member declaration with the dynamic modifier, access to that member is always dynamically dispatched using the Objective-C runtime. Access to that member is never inlined or devirtualized by the compiler.

Because declarations marked with the dynamic modifier are dispatched using the Objective-C runtime, they’re implicitly marked with the objc attribute.

我在我的另一个 Singleton 对象 BasicRadioApp 中从服务器获取数据。

我需要控制我的 Audio Session 与其他人(例如 Apple Watch)的交互,因此需要设置您的 AVAudioSessionCategory。我还想在 Apple Watch 音乐应用程序的锁屏和 Glance 上远程控制我的音频。

AVAudioSession类中,这个函数是这样声明的;

/* set session category */
public func setCategory(category: String) throws

如您所见,它们会抛出异常,因此您需要在错误处理中设置它们,例如 >Swift 2.0 的 do/try 概念。

让我们尝试播放声音;

final func playRadio() {

do {
try removeObserverFromRadioItem()
} catch {
print("Can not remove observer from AVPlayerItem object!")
}

radioItem = AVPlayerItem(URL: NSURL(string: dataModel.radioStreamUrl)!)
radioPlayer = AVPlayer(playerItem: radioItem!)
radioItem!.addObserver(self, forKeyPath: "status", options: [.New, .Initial, .Old], context: &radioContext)

if MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo == nil {

let albumArt = MPMediaItemArtwork(image: UIImage(named: "AlbumArt")!)
let songInfo: Dictionary = [MPMediaItemPropertyTitle: "Now listening Hard Rock Bla Bla FM",
MPMediaItemPropertyArtist: "My Radyo",
MPMediaItemPropertyAlbumTitle: "105.5 FM",
MPMediaItemPropertyArtwork: albumArt]

MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = songInfo
}
}

在声明我的 AVPlayerItem 之前,如果它存在,我需要删除它上面的 KVO。您将看到 removeObserverFromRadioItem() 接下来在做什么。我需要将我的 AVPlayerItem 注册到 KVO 对象,它会处理是否播放。正如我所说,我需要在锁定屏幕上远程控制我的音频,因此我为此使用了 MPNowPlayingInfoCenter

final func stopRadio() {
MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = nil
radioPlayer?.pause()
}

final func removeObserverFromRadioItem() throws {
radioItem?.removeObserver(self, forKeyPath: "status", context: &radioContext)
}

最重要的部分在这里;

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if object as? AVPlayerItem == radioPlayer?.currentItem && keyPath! == "status" {
if self.radioPlayer?.currentItem!.status == .Failed {
print("STREAM FAILED")
} else if self.radioPlayer?.currentItem!.status == .ReadyToPlay {
self.radioPlayer!.play()
radioDelegate?.RadioDidStartPlay()
}
return
}
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}

你如何从任何类(class)开始 radio ?

class RadioController: UIViewController {

let sharedRadioPlayer = RadioModel.sharedModel
..

override func viewDidLoad() {
super.viewDidLoad()

// check if radio is NOT playing
if sharedRadioPlayer.radioPlayer?.rate < 1 {
sharedRadioPlayer.playRadio()
}
}

最后一步是从锁屏上远程我的应用程序。停止、播放等。对于远程,我在 AppDelegateRadioModel 中调用我的方法。在 AppDelegate 中;

override func remoteControlReceivedWithEvent(event: UIEvent?) {
RadioModel.sharedModel.handleRemoteControlEvent(event!)
}

并在 radio 模型中;

func handleRemoteControlEvent(responseEvent: UIEvent) {
if responseEvent.type == UIEventType.RemoteControl {
switch(responseEvent.subtype) {
case UIEventSubtype.RemoteControlPlay:
playRadio()
break
case UIEventSubtype.RemoteControlPause:
stopRadio()
break
case UIEventSubtype.RemoteControlTogglePlayPause:
if self.radioPlayer!.rate > 0 {
stopRadio()
} else {
playRadio()
}
break
default:
print("Remote Error")
}
}
}

不要忘记在您的应用中 TARGETS > Capabilities > 打开背景模式并选择音频、AirPlay 和画中画。然后检查您的 info.plist 并搜索“需要背景模式”。如果它不存在,则创建一个新的数组并设置“App plays audio or streams audio/video using AirPlay”项。就是这样,您现在可以播放 airPlay 广播/流媒体了。

关于ios - 获取任何 AudioPlayer 来传输或播放音乐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34315602/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com