#ios #swift #airplay
Вопрос:
Я создал простой аудиоплеер в swift 5, который реализует представление AVRoutePicker. Выбор маршрута отображается без проблем, и я могу переключаться между наушниками, динамиками телефона и динамиками телефонных звонков.
Проблема, с которой я сталкиваюсь, заключается в том, что, как только я выбираю динамик Airplay, звук из моего приложения не воспроизводится через выбранный динамик Airplay, а вместо этого воспроизводится из динамика телефона, даже несмотря на то, что в указателе маршрута есть галочка рядом с устройством AirPlay.
Я могу успешно подключиться к динамику AirPlay и воспроизводить аудио через YouTube или spotify, поэтому я знаю, что это должно быть возможно.
Я надеюсь, что я допустил простую ошибку в своем коде — я не получаю никаких ошибок, поэтому его немного сложно отлаживать.
Мой код:
import UIKit
import AVFoundation //audio-video foundation
import AVKit
let rect = CGRect(x: 10, y: 10, width: 100, height: 100)
let myView = UIView(frame: rect)
class ViewController: UIViewController, AVAudioRecorderDelegate, UITableViewDelegate, UITableViewDataSource {
var recordingSession: AVAudioSession!
var audioRecorder: AVAudioRecorder!
var audioPlayer: AVAudioPlayer!
var numberOfRecords = 0
@IBOutlet weak var TestButton1: UIButton!
@IBOutlet weak var MyTableView: UITableView!
@IBOutlet weak var buttonLabel: UIButton!
@IBAction func record(_ sender: Any)
{
//Check if we have an active recorder
if audioRecorder == nil
{
numberOfRecords = 1
let filename = getDirectory().appendingPathComponent("(numberOfRecords).m4a")
let settings = [AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 12000, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue]
//Start rec
do
{
audioRecorder = try AVAudioRecorder(url: filename, settings: settings)
audioRecorder.delegate = self
audioRecorder.record()
buttonLabel.setTitle("Stop Recording", for: .normal)
}
catch
{
displayAlert(title:"Ups!", message: "Recording failed")
}
}
else
{
//stopping rec
audioRecorder.stop()
audioRecorder = nil
UserDefaults.standard.set(numberOfRecords, forKey: "myNumber")
MyTableView.reloadData()
buttonLabel.setTitle("Start Recording", for: .normal)
}
}
@IBAction func RoutePicker(_ sender: Any) {
let routePickerView = AVRoutePickerView()
self.view.addSubview(routePickerView)
if let routePickerButton = routePickerView.subviews.first(where: { $0 is UIButton }) as? UIButton {
routePickerButton.sendActions(for: .touchUpInside)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let routePickerView = AVRoutePickerView()
self.view.addSubview(routePickerView)
if let routePickerButton = routePickerView.subviews.first(where: { $0 is UIButton }) as? UIButton {
routePickerButton.sendActions(for: .touchUpInside)
}
//Setting up session
recordingSession = AVAudioSession.sharedInstance()
if let number:Int = UserDefaults.standard.object(forKey: "muNumber") as? Int
{
numberOfRecords = number
}
if (recordingSession.responds(to: #selector(AVAudioSession.requestRecordPermission(_:)))) {
AVAudioSession.sharedInstance().requestRecordPermission({(granted: Bool)-> Void in
if granted {
print("granted")
do {
try self.recordingSession.setCategory(AVAudioSession.Category.playAndRecord)
try self.recordingSession.setActive(true)
}
catch {
print("Couldn't set Audio session category")
}
} else{
print("not granted")
}
})
}
}
//Function that gets path to directory
func getDirectory() -> URL
{
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentDirectory = paths[0]
return documentDirectory
}
//Function that displays an alert
func displayAlert(title:String, message:String)
{
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "dismiss", style: .default, handler: nil))
present(alert, animated: true, completion: nil)
}
//SETTING UP TABLE VIEW//
func tableView (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfRecords
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = String(indexPath.row 1)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let path = getDirectory().appendingPathComponent("(indexPath.row 1).m4a")
do
{
// try recordingSession.overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
audioPlayer = try AVAudioPlayer(contentsOf: path)
audioPlayer.play()
}
catch
{
}
}
}
Я думаю, что линия try recordingSession.overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
здесь ключевая, так как, когда это не указано, мы не можем переключаться между динамиком телефона или наушниками.
Мне интересно, есть ли эквивалент для динамиков Airplay.
Xcode 12.5 Устройство IOS: 13.1.2 macOS: Big Sur 11.0.1 Swift: 4
Комментарии:
1. Кто-нибудь знает, правильны ли настройки здесь: т. е. поддерживает ли airplay файлы .m4a? #